Merge "Color correction string update" into sc-dev
diff --git a/Android.bp b/Android.bp
index e4c5c37..7099291 100644
--- a/Android.bp
+++ b/Android.bp
@@ -371,7 +371,6 @@
     srcs: [
         // Java/AIDL sources under frameworks/base
         ":framework-blobstore-sources",
-        ":framework-connectivity-sources", // framework-connectivity is not yet a module
         ":framework-core-sources",
         ":framework-drm-sources",
         ":framework-graphics-nonupdatable-sources",
@@ -422,6 +421,7 @@
         ":resourcemanager_aidl",
         ":storaged_aidl",
         ":vold_aidl",
+        ":deviceproductinfoconstants_aidl",
 
         // For the generated R.java and Manifest.java
         ":framework-res{.aapt.srcjar}",
@@ -437,6 +437,7 @@
     name: "framework-updatable-sources",
     srcs: [
         ":framework-appsearch-sources",
+        ":framework-connectivity-sources",
         ":framework-graphics-srcs",
         ":framework-mediaprovider-sources",
         ":framework-permission-sources",
@@ -583,6 +584,7 @@
         "android.security.apc-java",
         "android.security.authorization-java",
         "android.security.usermanager-java",
+        "android.security.vpnprofilestore-java",
         "android.system.keystore2-V1-java",
         "android.system.suspend.control.internal-java",
         "cameraprotosnano",
@@ -639,6 +641,7 @@
     defaults: ["framework-aidl-export-defaults"],
     srcs: [
         ":framework-non-updatable-sources",
+        ":framework-connectivity-sources",
         "core/java/**/*.logtags",
     ],
     // See comment on framework-atb-backward-compatibility module below
@@ -700,6 +703,8 @@
     apex_available: ["//apex_available:platform"],
     visibility: [
         "//frameworks/base",
+        // TODO: remove when framework-connectivity can build against API
+        "//frameworks/base/packages/Connectivity/framework",
         // TODO(b/147128803) remove the below lines
         "//frameworks/base/apex/appsearch/framework",
         "//frameworks/base/apex/blobstore/framework",
@@ -1452,6 +1457,7 @@
     ],
     libs: [
         "framework-annotations-lib",
+        "framework-connectivity",
         "unsupportedappusage",
     ],
     visibility: [
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 4bd524f..bff222e 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -58,6 +58,9 @@
         local_include_dirs: [
             "apex/media/aidl/stable",
             "media/aidl",
+            // TODO: move to include-dirs for packages/modules/Connectivity when this moves out of
+            // frameworks/base
+            "packages/Connectivity/framework/aidl-export",
             "telephony/java",
         ],
         include_dirs: ["frameworks/av/aidl"],
@@ -310,6 +313,7 @@
         "art.module.public.api.stubs",
         "conscrypt.module.public.api.stubs",
         "framework-appsearch.stubs",
+        "framework-connectivity.stubs",
         "framework-graphics.stubs",
         "framework-media.stubs",
         "framework-mediaprovider.stubs",
@@ -334,6 +338,7 @@
         "art.module.public.api.stubs",
         "conscrypt.module.public.api.stubs",
         "framework-appsearch.stubs.system",
+        "framework-connectivity.stubs.system",
         "framework-graphics.stubs.system",
         "framework-media.stubs.system",
         "framework-mediaprovider.stubs.system",
@@ -374,6 +379,7 @@
         "art.module.public.api.stubs",
         "conscrypt.module.public.api.stubs",
         "framework-appsearch.stubs.system",
+        "framework-connectivity.stubs.system",
         "framework-graphics.stubs.system",
         "framework-media.stubs.system",
         "framework-mediaprovider.stubs.system",
diff --git a/apct-tests/perftests/contentcapture/Android.bp b/apct-tests/perftests/contentcapture/Android.bp
index 19a66ad..638403d 100644
--- a/apct-tests/perftests/contentcapture/Android.bp
+++ b/apct-tests/perftests/contentcapture/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+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_test {
     name: "ContentCapturePerfTests",
     srcs: ["src/**/*.java"],
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java
index e83c64c..5a45961 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java
@@ -44,7 +44,7 @@
 @RunWith(AndroidJUnit4.class)
 public class TypefaceCreatePerfTest {
     // A font file name in asset directory.
-    private static final String TEST_FONT_NAME = "DancingScript-Regular.ttf";
+    private static final String TEST_FONT_NAME = "DancingScript.ttf";
 
     @Rule
     public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
diff --git a/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt b/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt
index 1d94d7e..d5ed95f 100644
--- a/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt
+++ b/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt
@@ -97,11 +97,21 @@
     private val state: BenchmarkState get() = perfStatusReporter.benchmarkState
     private val apks: List<File> get() = params.apks
 
+    private fun safeParse(parser: ParallelParser<*>, file: File) {
+        try {
+            parser.parse(file)
+        } catch (e: Exception) {
+            // ignore
+        }
+    }
+
     @Test
     fun sequentialNoCache() {
         params.cacheDirToParser(null).use { parser ->
             while (state.keepRunning()) {
-                apks.forEach { parser.parse(it) }
+                apks.forEach {
+                    safeParse(parser, it)
+                }
             }
         }
     }
@@ -110,10 +120,10 @@
     fun sequentialCached() {
         params.cacheDirToParser(testFolder.newFolder()).use { parser ->
             // Fill the cache
-            apks.forEach { parser.parse(it) }
+            apks.forEach { safeParse(parser, it) }
 
             while (state.keepRunning()) {
-                apks.forEach { parser.parse(it) }
+                apks.forEach { safeParse(parser, it) }
             }
         }
     }
@@ -132,7 +142,7 @@
     fun parallelCached() {
         params.cacheDirToParser(testFolder.newFolder()).use { parser ->
             // Fill the cache
-            apks.forEach { parser.parse(it) }
+            apks.forEach { safeParse(parser, it) }
 
             while (state.keepRunning()) {
                 apks.forEach { parser.submit(it) }
diff --git a/apct-tests/perftests/inputmethod/Android.bp b/apct-tests/perftests/inputmethod/Android.bp
index 463ac9b..f2f1f75 100644
--- a/apct-tests/perftests/inputmethod/Android.bp
+++ b/apct-tests/perftests/inputmethod/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+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_test {
     name: "ImePerfTests",
     srcs: ["src/**/*.java"],
diff --git a/apex/appsearch/Android.bp b/apex/appsearch/Android.bp
index ab44dd9..87f65a9 100644
--- a/apex/appsearch/Android.bp
+++ b/apex/appsearch/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+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"],
+}
+
 apex {
     name: "com.android.appsearch",
     manifest: "apex_manifest.json",
diff --git a/apex/appsearch/framework/Android.bp b/apex/appsearch/framework/Android.bp
index 8ba7954..5def55f 100644
--- a/apex/appsearch/framework/Android.bp
+++ b/apex/appsearch/framework/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 filegroup {
     name: "framework-appsearch-sources",
     srcs: [
diff --git a/apex/appsearch/framework/api/current.txt b/apex/appsearch/framework/api/current.txt
index cc79f6b..168c7c2 100644
--- a/apex/appsearch/framework/api/current.txt
+++ b/apex/appsearch/framework/api/current.txt
@@ -148,7 +148,7 @@
     method public void remove(@NonNull android.app.appsearch.RemoveByUriRequest, @NonNull java.util.concurrent.Executor, @NonNull android.app.appsearch.BatchResultCallback<java.lang.String,java.lang.Void>);
     method public void remove(@NonNull String, @NonNull android.app.appsearch.SearchSpec, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.lang.Void>>);
     method public void reportUsage(@NonNull android.app.appsearch.ReportUsageRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.lang.Void>>);
-    method @NonNull public android.app.appsearch.SearchResults search(@NonNull String, @NonNull android.app.appsearch.SearchSpec, @NonNull java.util.concurrent.Executor);
+    method @NonNull public android.app.appsearch.SearchResults search(@NonNull String, @NonNull android.app.appsearch.SearchSpec);
     method public void setSchema(@NonNull android.app.appsearch.SetSchemaRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<android.app.appsearch.SetSchemaResponse>>);
   }
 
@@ -217,7 +217,7 @@
 
   public class GlobalSearchSession implements java.io.Closeable {
     method public void close();
-    method @NonNull public android.app.appsearch.SearchResults search(@NonNull String, @NonNull android.app.appsearch.SearchSpec, @NonNull java.util.concurrent.Executor);
+    method @NonNull public android.app.appsearch.SearchResults search(@NonNull String, @NonNull android.app.appsearch.SearchSpec);
   }
 
   public class PackageIdentifier {
@@ -287,7 +287,7 @@
 
   public class SearchResults implements java.io.Closeable {
     method public void close();
-    method public void getNextPage(@NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.util.List<android.app.appsearch.SearchResult>>>);
+    method public void getNextPage(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.util.List<android.app.appsearch.SearchResult>>>);
   }
 
   public final class SearchSpec {
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java
index 519c14f..31ab259 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java
@@ -28,11 +28,19 @@
 import java.util.Map;
 
 /**
- * Provides access to multiple {@link AppSearchResult}s from a batch operation accepting multiple
- * inputs.
+ * Provides results for AppSearch batch operations which encompass multiple documents.
  *
- * @param <KeyType> The type of the keys for {@link #getSuccesses} and {@link #getFailures}.
- * @param <ValueType> The type of result objects associated with the keys.
+ * <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.
+ *
+ * @see AppSearchSession#put
+ * @see AppSearchSession#getByUri
+ * @see AppSearchSession#remove
  */
 public final class AppSearchBatchResult<KeyType, ValueType> implements Parcelable {
     @NonNull private final Map<KeyType, ValueType> mSuccesses;
@@ -75,8 +83,11 @@
     }
 
     /**
-     * Returns a {@link Map} of all successful keys mapped to the successful {@link
-     * AppSearchResult}s they produced.
+     * Returns a {@link Map} of keys mapped to instances of the value type for all successful
+     * individual results.
+     *
+     * <p>Example: {@link AppSearchSession#getByUri} returns an {@link AppSearchBatchResult}. Each
+     * key (a URI of {@code String} type) will map to a {@link GenericDocument} object.
      *
      * <p>The values of the {@link Map} will not be {@code null}.
      */
@@ -86,8 +97,8 @@
     }
 
     /**
-     * Returns a {@link Map} of all failed keys mapped to the failed {@link AppSearchResult}s they
-     * produced.
+     * 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}.
      */
@@ -97,7 +108,8 @@
     }
 
     /**
-     * Returns a {@link Map} of all keys mapped to the {@link AppSearchResult}s they produced.
+     * Returns a {@link Map} of keys mapped to instances of {@link AppSearchResult} for all
+     * individual results.
      *
      * <p>The values of the {@link Map} will not be {@code null}.
      */
@@ -149,8 +161,8 @@
     /**
      * Builder for {@link AppSearchBatchResult} objects.
      *
-     * @param <KeyType> The type of keys.
-     * @param <ValueType> The type of result objects associated with the keys.
+     * <p>Once {@link #build} is called, the instance can no longer be used.
+     *
      * @hide
      */
     public static final class Builder<KeyType, ValueType> {
@@ -160,9 +172,11 @@
         private boolean mBuilt = false;
 
         /**
-         * Associates the {@code key} with the given successful return value.
+         * 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.
          */
         @NonNull
         public Builder<KeyType, ValueType> setSuccess(
@@ -173,9 +187,11 @@
         }
 
         /**
-         * Associates the {@code key} with the given failure code and error message.
+         * 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.
          */
         @NonNull
         public Builder<KeyType, ValueType> setFailure(
@@ -188,9 +204,11 @@
         }
 
         /**
-         * Associates the {@code key} with the given {@code result}.
+         * 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.
          */
         @NonNull
         public Builder<KeyType, ValueType> setResult(
@@ -209,7 +227,11 @@
             return this;
         }
 
-        /** Builds an {@link AppSearchBatchResult} from the contents of this {@link Builder}. */
+        /**
+         * 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");
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
index 3c02d10..24cc60e 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
@@ -41,7 +41,7 @@
  * Represents a connection to an AppSearch storage system where {@link GenericDocument}s can be
  * placed and queried.
  *
- * This class is thread safe.
+ * <p>This class is thread safe.
  */
 public final class AppSearchSession implements Closeable {
     private static final String TAG = "AppSearchSession";
@@ -102,92 +102,23 @@
     }
 
     /**
-     * Sets the schema that will be used by documents provided to the {@link #put} method.
+     * Sets the schema that represents the organizational structure of data within the AppSearch
+     * database.
      *
-     * <p>The schema provided here is compared to the stored copy of the schema previously supplied
-     * to {@link #setSchema}, if any, to determine how to treat existing documents. The following
-     * types of schema modifications are always safe and are made without deleting any existing
-     * documents:
+     * <p>Upon creating an {@link AppSearchSession}, {@link #setSchema} should be called. If the
+     * schema needs to be updated, or it has not been previously set, then the provided schema will
+     * be saved and persisted to disk. Otherwise, {@link #setSchema} is handled efficiently as a
+     * no-op call.
      *
-     * <ul>
-     *   <li>Addition of new types
-     *   <li>Addition of new {@link AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} or
-     *       {@link AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED} properties to a
-     *       type
-     *   <li>Changing the cardinality of a data type to be less restrictive (e.g. changing an {@link
-     *       AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} property into a {@link
-     *       AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED} property.
-     * </ul>
-     *
-     * <p>The following types of schema changes are not backwards-compatible:
-     *
-     * <ul>
-     *   <li>Removal of an existing type
-     *   <li>Removal of a property from a type
-     *   <li>Changing the data type ({@code boolean}, {@code long}, etc.) of an existing property
-     *   <li>For properties of {@code Document} type, changing the schema type of {@code Document}s
-     *       of that property
-     *   <li>Changing the cardinality of a data type to be more restrictive (e.g. changing an {@link
-     *       AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} property into a {@link
-     *       AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} property).
-     *   <li>Adding a {@link AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} property.
-     * </ul>
-     *
-     * <p>Supplying a schema with such changes will, by default, result in this call completing its
-     * future with an {@link android.app.appsearch.exceptions.AppSearchException} with a code of
-     * {@link AppSearchResult#RESULT_INVALID_SCHEMA} and a message describing the incompatibility.
-     * In this case the previously set schema will remain active.
-     *
-     * <p>If you need to make non-backwards-compatible changes as described above, you can either:
-     *
-     * <ul>
-     *   <li>Set the {@link SetSchemaRequest.Builder#setForceOverride} method to {@code true}. In
-     *       this case, instead of completing its future with an {@link
-     *       android.app.appsearch.exceptions.AppSearchException} with the {@link
-     *       AppSearchResult#RESULT_INVALID_SCHEMA} error code, all documents which are not
-     *       compatible with the new schema will be deleted and the incompatible schema will be
-     *       applied. Incompatible types and deleted types will be set into {@link
-     *       SetSchemaResponse#getIncompatibleTypes()} and {@link
-     *       SetSchemaResponse#getDeletedTypes()}, respectively.
-     *   <li>Add a {@link android.app.appsearch.AppSearchSchema.Migrator} for each incompatible type
-     *       and make no deletion. The migrator will migrate documents from it's old schema version
-     *       to the new version. Migrated types will be set into both {@link
-     *       SetSchemaResponse#getIncompatibleTypes()} and {@link
-     *       SetSchemaResponse#getMigratedTypes()}. See the migration section below.
-     * </ul>
-     *
-     * <p>It is a no-op to set the same schema as has been previously set; this is handled
-     * efficiently.
-     *
-     * <p>By default, documents are visible on platform surfaces. To opt out, call {@code
-     * SetSchemaRequest.Builder#setPlatformSurfaceable} with {@code surfaceable} as false. Any
-     * visibility settings apply only to the schemas that are included in the {@code request}.
-     * Visibility settings for a schema type do not apply or persist across {@link
-     * SetSchemaRequest}s.
-     *
-     * <p>Migration: make non-backwards-compatible changes will delete all stored documents in old
-     * schema. You can save your documents by setting {@link
-     * android.app.appsearch.AppSearchSchema.Migrator} via the {@link
-     * SetSchemaRequest.Builder#setMigrator} for each type you want to save.
-     *
-     * <p>{@link android.app.appsearch.AppSearchSchema.Migrator#onDowngrade} or {@link
-     * android.app.appsearch.AppSearchSchema.Migrator#onUpgrade} will be triggered if the version
-     * number of the schema stored in AppSearch is different with the version in the request.
-     *
-     * <p>If any error or Exception occurred in the {@link
-     * android.app.appsearch.AppSearchSchema.Migrator#onDowngrade}, {@link
-     * android.app.appsearch.AppSearchSchema.Migrator#onUpgrade} or {@link
-     * android.app.appsearch.AppSearchMigrationHelper.Transformer#transform}, the migration will be
-     * terminated, the setSchema request will be rejected unless the schema changes are
-     * backwards-compatible, and stored documents won't have any observable changes.
-     *
-     * @param request The schema update request.
+     * @param request the schema to set or update the AppSearch database to.
      * @param executor Executor on which to invoke the callback.
      * @param callback Callback to receive errors resulting from setting the schema. If the
      *                 operation succeeds, the callback will be invoked with {@code null}.
      * @see android.app.appsearch.AppSearchSchema.Migrator
      * @see android.app.appsearch.AppSearchMigrationHelper.Transformer
      */
+    // TODO(b/169883602): Change @code references to @link when setPlatformSurfaceable APIs are
+    //  exposed.
     public void setSchema(
             @NonNull SetSchemaRequest request,
             @NonNull @CallbackExecutor Executor executor,
@@ -280,12 +211,13 @@
     }
 
     /**
-     * Indexes documents into AppSearch.
+     * Indexes documents into the {@link AppSearchSession} database.
      *
-     * <p>Each {@link GenericDocument}'s {@code schemaType} field must be set to the name of a
-     * schema type previously registered via the {@link #setSchema} method.
+     * <p>Each {@link GenericDocument} object must have a {@code schemaType} field set to an {@link
+     * AppSearchSchema} type that has been previously registered by calling the {@link #setSchema}
+     * method.
      *
-     * @param request {@link PutDocumentsRequest} containing documents to be indexed
+     * @param request containing documents to be indexed.
      * @param executor Executor on which to invoke the callback.
      * @param callback Callback to receive pending result of performing this operation. The keys
      *                 of the returned {@link AppSearchBatchResult} are the URIs of the input
@@ -463,21 +395,15 @@
      * @param queryExpression query string to search.
      * @param searchSpec spec for setting document filters, adding projection, setting term match
      *     type, etc.
-     * @param executor        Executor on which to invoke the callback of the following request
-     *                        {@link SearchResults#getNextPage}.
      * @return a {@link SearchResults} object for retrieved matched documents.
      */
     @NonNull
-    public SearchResults search(
-            @NonNull String queryExpression,
-            @NonNull SearchSpec searchSpec,
-            @NonNull @CallbackExecutor Executor executor) {
+    public SearchResults search(@NonNull String queryExpression, @NonNull SearchSpec searchSpec) {
         Objects.requireNonNull(queryExpression);
         Objects.requireNonNull(searchSpec);
-        Objects.requireNonNull(executor);
         Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
         return new SearchResults(mService, mPackageName, mDatabaseName, queryExpression,
-                searchSpec, mUserId, executor);
+                searchSpec, mUserId);
     }
 
     /**
diff --git a/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
index 09bca4f..8dd9dc1 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
@@ -98,8 +98,7 @@
      * <p>Document access can also be granted to system UIs by specifying {@link
      * SetSchemaRequest.Builder#setSchemaTypeVisibilityForSystemUi} when building a schema.
      *
-     * <p>See {@link AppSearchSession#search} for a detailed explanation on
-     * forming a query string.
+     * <p>See {@link AppSearchSession#search} for a detailed explanation on forming a query string.
      *
      * <p>This method is lightweight. The heavy work will be done in {@link
      * SearchResults#getNextPage}.
@@ -107,21 +106,15 @@
      * @param queryExpression query string to search.
      * @param searchSpec spec for setting document filters, adding projection, setting term match
      *     type, etc.
-     * @param executor        Executor on which to invoke the callback of the following request
-     *                        {@link SearchResults#getNextPage}.
      * @return a {@link SearchResults} object for retrieved matched documents.
      */
     @NonNull
-    public SearchResults search(
-            @NonNull String queryExpression,
-            @NonNull SearchSpec searchSpec,
-            @NonNull @CallbackExecutor Executor executor) {
+    public SearchResults search(@NonNull String queryExpression, @NonNull SearchSpec searchSpec) {
         Objects.requireNonNull(queryExpression);
         Objects.requireNonNull(searchSpec);
-        Objects.requireNonNull(executor);
         Preconditions.checkState(!mIsClosed, "GlobalSearchSession has already been closed");
         return new SearchResults(mService, mPackageName, /*databaseName=*/null, queryExpression,
-                searchSpec, mUserId, executor);
+                searchSpec, mUserId);
     }
 
     /** Closes the {@link GlobalSearchSession}. */
diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
index a63e015..531c984 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
@@ -33,12 +33,16 @@
 import java.util.function.Consumer;
 
 /**
- * SearchResults are a returned object from a query API.
+ * Encapsulates results of a search operation.
  *
- * <p>Each {@link SearchResult} contains a document and may contain other fields like snippets based
- * on request.
+ * <p>Each {@link AppSearchSession#search} operation returns a list of {@link SearchResult} objects,
+ * referred to as a "page", limited by the size configured by {@link
+ * SearchSpec.Builder#setResultCountPerPage}.
  *
- * <p>Should close this object after finish fetching results.
+ * <p>To fetch a page of results, call {@link #getNextPage}.
+ *
+ * <p>All instances of {@link SearchResults} must call {@link SearchResults#close()} after the
+ * results are fetched.
  *
  * <p>This class is not thread safe.
  */
@@ -61,8 +65,6 @@
     @UserIdInt
     private final int mUserId;
 
-    private final Executor mExecutor;
-
     private long mNextPageToken;
 
     private boolean mIsFirstLoad = true;
@@ -75,28 +77,31 @@
             @Nullable String databaseName,
             @NonNull String queryExpression,
             @NonNull SearchSpec searchSpec,
-            @UserIdInt int userId,
-            @NonNull @CallbackExecutor Executor executor) {
+            @UserIdInt int userId) {
         mService = Objects.requireNonNull(service);
         mPackageName = packageName;
         mDatabaseName = databaseName;
         mQueryExpression = Objects.requireNonNull(queryExpression);
         mSearchSpec = Objects.requireNonNull(searchSpec);
         mUserId = userId;
-        mExecutor = Objects.requireNonNull(executor);
     }
 
     /**
-     * Gets a whole page of {@link SearchResult}s.
+     * Retrieves the next page of {@link SearchResult} objects.
      *
-     * <p>Re-call this method to get next page of {@link SearchResult}, until it returns an empty
-     * list.
+     * <p>The page size is configured by {@link SearchSpec.Builder#setResultCountPerPage}.
      *
-     * <p>The page size is set by {@link SearchSpec.Builder#setResultCountPerPage}.
+     * <p>Continue calling this method to access results until it returns an empty list, signifying
+     * there are no more results.
      *
+     * @param executor Executor on which to invoke the callback.
      * @param callback Callback to receive the pending result of performing this operation.
      */
-    public void getNextPage(@NonNull Consumer<AppSearchResult<List<SearchResult>>> callback) {
+    public void getNextPage(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull Consumer<AppSearchResult<List<SearchResult>>> callback) {
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
         Preconditions.checkState(!mIsClosed, "SearchResults has already been closed");
         try {
             if (mIsFirstLoad) {
@@ -104,14 +109,14 @@
                 if (mDatabaseName == null) {
                     // Global query, there's no one package-database combination to check.
                     mService.globalQuery(mPackageName, mQueryExpression,
-                            mSearchSpec.getBundle(), mUserId, wrapCallback(callback));
+                            mSearchSpec.getBundle(), mUserId, wrapCallback(executor, callback));
                 } else {
                     // Normal local query, pass in specified database.
                     mService.query(mPackageName, mDatabaseName, mQueryExpression,
-                            mSearchSpec.getBundle(), mUserId, wrapCallback(callback));
+                            mSearchSpec.getBundle(), mUserId, wrapCallback(executor, callback));
                 }
             } else {
-                mService.getNextPage(mNextPageToken, mUserId, wrapCallback(callback));
+                mService.getNextPage(mNextPageToken, mUserId, wrapCallback(executor, callback));
             }
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -131,10 +136,11 @@
     }
 
     private IAppSearchResultCallback wrapCallback(
+            @NonNull @CallbackExecutor Executor executor,
             @NonNull Consumer<AppSearchResult<List<SearchResult>>> callback) {
         return new IAppSearchResultCallback.Stub() {
             public void onResult(AppSearchResult result) {
-                mExecutor.execute(() -> invokeCallback(result, callback));
+                executor.execute(() -> invokeCallback(result, callback));
             }
         };
     }
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 57700f8..01473be 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java
@@ -30,8 +30,6 @@
 /**
  * Encapsulates a request to index documents into an {@link AppSearchSession} database.
  *
- * <p>@see AppSearchSession#putDocuments
- *
  * @see AppSearchSession#put
  */
 public final class PutDocumentsRequest {
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 2caa94a5e..426a903 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
@@ -32,6 +32,41 @@
 /**
  * Encapsulates a request to update the schema of an {@link AppSearchSession} database.
  *
+ * <p>The schema is composed of a collection of {@link AppSearchSchema} objects, each of which
+ * defines a unique type of data.
+ *
+ * <p>The first call to SetSchemaRequest will set the provided schema and store it within the {@link
+ * AppSearchSession} database.
+ *
+ * <p>Subsequent calls will compare the provided schema to the previously saved schema, to determine
+ * how to treat existing documents.
+ *
+ * <p>The following types of schema modifications are always safe and are made without deleting any
+ * existing documents:
+ *
+ * <ul>
+ *   <li>Addition of new {@link AppSearchSchema} types
+ *   <li>Addition of new properties to an existing {@link AppSearchSchema} type
+ *   <li>Changing the cardinality of a property to be less restrictive
+ * </ul>
+ *
+ * <p>The following types of schema changes are not backwards compatible:
+ *
+ * <ul>
+ *   <li>Removal of an existing {@link AppSearchSchema} type
+ *   <li>Removal of a property from an existing {@link AppSearchSchema} type
+ *   <li>Changing the data type of an existing property
+ *   <li>Changing the cardinality of a property to be more restrictive
+ * </ul>
+ *
+ * <p>Providing a schema with incompatible changes, will throw an {@link
+ * android.app.appsearch.exceptions.AppSearchException}, with a message describing the
+ * incompatibility. As a result, the previously set schema will remain unchanged.
+ *
+ * <p>Backward incompatible changes can be made by setting {@link
+ * SetSchemaRequest.Builder#setForceOverride} method to {@code true}. This deletes all documents
+ * that are incompatible with the new schema. The new schema is then saved and persisted to disk.
+ *
  * @see AppSearchSession#setSchema
  */
 public final class SetSchemaRequest {
@@ -54,14 +89,15 @@
         mForceOverride = forceOverride;
     }
 
-    /** Returns the schemas that are part of this request. */
+    /** Returns the {@link AppSearchSchema} types that are part of this request. */
     @NonNull
     public Set<AppSearchSchema> getSchemas() {
         return Collections.unmodifiableSet(mSchemas);
     }
 
     /**
-     * Returns the set of schema types that have opted out of being visible on system UI surfaces.
+     * Returns all the schema types that are opted out of being displayed and visible on any system
+     * UI surface.
      */
     @NonNull
     public Set<String> getSchemasNotVisibleToSystemUi() {
@@ -70,10 +106,9 @@
 
     /**
      * Returns a mapping of schema types to the set of packages that have access to that schema
-     * type. Each package is represented by a {@link PackageIdentifier}. name and byte[]
-     * certificate.
+     * type.
      *
-     * <p>This method is inefficient to call repeatedly.
+     * <p>It’s inefficient to call this method repeatedly.
      */
     @NonNull
     public Map<String, Set<PackageIdentifier>> getSchemasVisibleToPackages() {
@@ -91,9 +126,8 @@
     }
 
     /**
-     * Returns a mapping of schema types to the set of packages that have access to that schema
-     * type. Each package is represented by a {@link PackageIdentifier}. name and byte[]
-     * certificate.
+     * Returns a mapping of {@link AppSearchSchema} types to the set of packages that have access to
+     * that schema type.
      *
      * <p>A more efficient version of {@link #getSchemasVisibleToPackages}, but it returns a
      * modifiable map. This is not meant to be unhidden and should only be used by internal classes.
@@ -110,7 +144,11 @@
         return mForceOverride;
     }
 
-    /** Builder for {@link SetSchemaRequest} objects. */
+    /**
+     * Builder for {@link SetSchemaRequest} objects.
+     *
+     * <p>Once {@link #build} is called, the instance can no longer be used.
+     */
     public static final class Builder {
         private final Set<AppSearchSchema> mSchemas = new ArraySet<>();
         private final Set<String> mSchemasNotVisibleToSystemUi = new ArraySet<>();
@@ -121,9 +159,11 @@
         private boolean mBuilt = false;
 
         /**
-         * Adds one or more types to the schema.
+         * Adds one or more {@link AppSearchSchema} types to the schema.
          *
-         * <p>Any documents of these types will be visible on system UI surfaces by default.
+         * <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 AppSearchSchema... schemas) {
@@ -132,9 +172,11 @@
         }
 
         /**
-         * Adds one or more types to the schema.
+         * Adds a collection of {@link AppSearchSchema} objects to the schema.
          *
-         * <p>Any documents of these types will be visible on system UI surfaces by default.
+         * <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) {
@@ -145,10 +187,17 @@
         }
 
         /**
-         * Sets visibility on system UI surfaces for the given {@code schemaType}.
+         * Sets whether or not documents from the provided {@code schemaType} will be displayed and
+         * visible on any system UI surface.
+         *
+         * <p>This setting applies to the provided {@code schemaType} only, and does not persist
+         * across {@link AppSearchSession#setSchema} calls.
+         *
+         * <p>By default, documents are displayed and visible on system UI surfaces.
          *
          * @param schemaType The schema type to set visibility on.
          * @param visible Whether the {@code schemaType} will be visible or not.
+         * @throws IllegalStateException if the builder has already been used.
          */
         // Merged list available from getSchemasNotVisibleToSystemUi
         @SuppressLint("MissingGetterMatchingBuilder")
@@ -167,11 +216,25 @@
         }
 
         /**
-         * Sets visibility for a package for the given {@code schemaType}.
+         * Sets whether or not documents from the provided {@code schemaType} can be read by the
+         * specified package.
+         *
+         * <p>Each package is represented by a {@link PackageIdentifier}, containing a package name
+         * and a byte array of type {@link android.content.pm.PackageManager#CERT_INPUT_SHA256}.
+         *
+         * <p>To opt into one-way data sharing with another application, the developer will need to
+         * explicitly grant the other application’s package name and certificate Read access to its
+         * data.
+         *
+         * <p>For two-way data sharing, both applications need to explicitly grant Read access to
+         * one another.
+         *
+         * <p>By default, data sharing between applications is disabled.
          *
          * @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")
@@ -224,13 +287,15 @@
         }
 
         /**
-         * Configures the {@link SetSchemaRequest} to delete any existing documents that don't
-         * follow the new schema.
+         * Sets whether or not to override the current schema in the {@link AppSearchSession}
+         * database.
          *
-         * <p>By default, this is {@code false} and schema incompatibility causes the {@link
-         * AppSearchSession#setSchema} call to fail.
+         * <p>Call this method whenever backward incompatible changes need to be made by setting
+         * {@code forceOverride} to {@code true}. As a result, during execution of the setSchema
+         * operation, all documents that are incompatible with the new schema will be deleted and
+         * the new schema will be saved and persisted.
          *
-         * @see AppSearchSession#setSchema
+         * <p>By default, this is {@code false}.
          */
         @NonNull
         public Builder setForceOverride(boolean forceOverride) {
@@ -239,10 +304,11 @@
         }
 
         /**
-         * Builds a new {@link SetSchemaRequest}.
+         * Builds a new {@link SetSchemaRequest} object.
          *
-         * @throws IllegalArgumentException If schema types were referenced, but the corresponding
-         *     {@link AppSearchSchema} was never added.
+         * @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() {
diff --git a/apex/appsearch/service/Android.bp b/apex/appsearch/service/Android.bp
index 2fd5c73..57ee1ec 100644
--- a/apex/appsearch/service/Android.bp
+++ b/apex/appsearch/service/Android.bp
@@ -11,6 +11,15 @@
 // 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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 java_library {
     name: "service-appsearch",
     installable: true,
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
index 6c2e30e..e2c211b 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
@@ -654,6 +654,35 @@
         }
     }
 
+    /**
+     * Returns a mapping of package names to all the databases owned by that package.
+     *
+     * <p>This method is inefficient to call repeatedly.
+     */
+    @NonNull
+    public Map<String, Set<String>> getPackageToDatabases() {
+        mReadWriteLock.readLock().lock();
+        try {
+            Map<String, Set<String>> packageToDatabases = new ArrayMap<>();
+            for (String prefix : mSchemaMapLocked.keySet()) {
+                String packageName = getPackageName(prefix);
+
+                Set<String> databases = packageToDatabases.get(packageName);
+                if (databases == null) {
+                    databases = new ArraySet<>();
+                    packageToDatabases.put(packageName, databases);
+                }
+
+                String databaseName = getDatabaseName(prefix);
+                databases.add(databaseName);
+            }
+
+            return packageToDatabases;
+        } finally {
+            mReadWriteLock.readLock().unlock();
+        }
+    }
+
     @GuardedBy("mReadWriteLock")
     private SearchResultPage doQueryLocked(
             @NonNull Set<String> prefixes,
@@ -1211,26 +1240,8 @@
         return schemaProto.getSchema();
     }
 
-    /**
-     * Returns true if the {@code packageName} and {@code databaseName} has the {@code schemaType}
-     */
-    @GuardedBy("mReadWriteLock")
-    boolean hasSchemaTypeLocked(
-            @NonNull String packageName, @NonNull String databaseName, @NonNull String schemaType) {
-        Preconditions.checkNotNull(packageName);
-        Preconditions.checkNotNull(databaseName);
-        Preconditions.checkNotNull(schemaType);
-
-        String prefix = createPrefix(packageName, databaseName);
-        Set<String> schemaTypes = mSchemaMapLocked.get(prefix);
-        if (schemaTypes == null) {
-            return false;
-        }
-
-        return schemaTypes.contains(prefix + schemaType);
-    }
-
     /** Returns a set of all prefixes AppSearchImpl knows about. */
+    // TODO(b/180058203): Remove this method once platform has switched away from using this method.
     @GuardedBy("mReadWriteLock")
     @NonNull
     Set<String> getPrefixesLocked() {
diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt
index fc0299e..2c9477a 100644
--- a/apex/appsearch/synced_jetpack_changeid.txt
+++ b/apex/appsearch/synced_jetpack_changeid.txt
@@ -1 +1 @@
-I895f5fb3bcb4be0642c6193000e57d80aafe2166
+I593dfd22279739e5f578e07d36a55cf02ee942c5
diff --git a/apex/appsearch/testing/Android.bp b/apex/appsearch/testing/Android.bp
index 54d5039..eb072af 100644
--- a/apex/appsearch/testing/Android.bp
+++ b/apex/appsearch/testing/Android.bp
@@ -11,6 +11,15 @@
 // 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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 java_library {
     name: "AppSearchTestUtils",
     srcs: ["java/**/*.java"],
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 afa633a..9ef6e0b 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
@@ -124,8 +124,7 @@
     @NonNull
     public SearchResultsShim search(
             @NonNull String queryExpression, @NonNull SearchSpec searchSpec) {
-        SearchResults searchResults =
-                mAppSearchSession.search(queryExpression, searchSpec, mExecutor);
+        SearchResults searchResults = mAppSearchSession.search(queryExpression, searchSpec);
         return new SearchResultsShimImpl(searchResults, mExecutor);
     }
 
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java
index 6595d8d..69a4c18 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java
@@ -75,8 +75,7 @@
     @Override
     public SearchResultsShim search(
             @NonNull String queryExpression, @NonNull SearchSpec searchSpec) {
-        SearchResults searchResults =
-                mGlobalSearchSession.search(queryExpression, searchSpec, mExecutor);
+        SearchResults searchResults = mGlobalSearchSession.search(queryExpression, searchSpec);
         return new SearchResultsShimImpl(searchResults, mExecutor);
     }
 
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/SearchResultsShimImpl.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/SearchResultsShimImpl.java
index 75add81..5f26e8c 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/SearchResultsShimImpl.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/SearchResultsShimImpl.java
@@ -47,7 +47,7 @@
     @NonNull
     public ListenableFuture<List<SearchResult>> getNextPage() {
         SettableFuture<AppSearchResult<List<SearchResult>>> future = SettableFuture.create();
-        mSearchResults.getNextPage(future::set);
+        mSearchResults.getNextPage(mExecutor, future::set);
         return Futures.transform(future, AppSearchResult::getResultValue, mExecutor);
     }
 
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java
index 34c7ccb..1428fb1 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java
@@ -33,90 +33,16 @@
 public interface AppSearchSessionShim extends Closeable {
 
     /**
-     * Sets the schema that will be used by documents provided to the {@link #put} method.
+     * Sets the schema that represents the organizational structure of data within the AppSearch
+     * database.
      *
-     * <p>The schema provided here is compared to the stored copy of the schema previously supplied
-     * to {@link #setSchema}, if any, to determine how to treat existing documents. The following
-     * types of schema modifications are always safe and are made without deleting any existing
-     * documents:
+     * <p>Upon creating an {@link AppSearchSessionShim}, {@link #setSchema} should be called. If the
+     * schema needs to be updated, or it has not been previously set, then the provided schema will
+     * be saved and persisted to disk. Otherwise, {@link #setSchema} is handled efficiently as a
+     * no-op call.
      *
-     * <ul>
-     *   <li>Addition of new types
-     *   <li>Addition of new {@link AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} or
-     *       {@link AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED} properties to a
-     *       type
-     *   <li>Changing the cardinality of a data type to be less restrictive (e.g. changing an {@link
-     *       AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} property into a {@link
-     *       AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED} property.
-     * </ul>
-     *
-     * <p>The following types of schema changes are not backwards-compatible:
-     *
-     * <ul>
-     *   <li>Removal of an existing type
-     *   <li>Removal of a property from a type
-     *   <li>Changing the data type ({@code boolean}, {@code long}, etc.) of an existing property
-     *   <li>For properties of {@code Document} type, changing the schema type of {@code Document}s
-     *       of that property
-     *   <li>Changing the cardinality of a data type to be more restrictive (e.g. changing an {@link
-     *       AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} property into a {@link
-     *       AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} property).
-     *   <li>Adding a {@link AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} property.
-     * </ul>
-     *
-     * <p>Supplying a schema with such changes will, by default, result in this call completing its
-     * future with an {@link android.app.appsearch.exceptions.AppSearchException} with a code of
-     * {@link AppSearchResult#RESULT_INVALID_SCHEMA} and a message describing the incompatibility.
-     * In this case the previously set schema will remain active.
-     *
-     * <p>If you need to make non-backwards-compatible changes as described above, you can either:
-     *
-     * <ul>
-     *   <li>Set the {@link SetSchemaRequest.Builder#setForceOverride} method to {@code true}. In
-     *       this case, instead of completing its future with an {@link
-     *       android.app.appsearch.exceptions.AppSearchException} with the {@link
-     *       AppSearchResult#RESULT_INVALID_SCHEMA} error code, all documents which are not
-     *       compatible with the new schema will be deleted and the incompatible schema will be
-     *       applied. Incompatible types and deleted types will be set into {@link
-     *       SetSchemaResponse#getIncompatibleTypes()} and {@link
-     *       SetSchemaResponse#getDeletedTypes()}, respectively.
-     *   <li>Add a {@link android.app.appsearch.AppSearchSchema.Migrator} for each incompatible type
-     *       and make no deletion. The migrator will migrate documents from it's old schema version
-     *       to the new version. Migrated types will be set into both {@link
-     *       SetSchemaResponse#getIncompatibleTypes()} and {@link
-     *       SetSchemaResponse#getMigratedTypes()}. See the migration section below.
-     * </ul>
-     *
-     * <p>It is a no-op to set the same schema as has been previously set; this is handled
-     * efficiently.
-     *
-     * <p>By default, documents are visible on platform surfaces. To opt out, call {@code
-     * SetSchemaRequest.Builder#setPlatformSurfaceable} with {@code surfaceable} as false. Any
-     * visibility settings apply only to the schemas that are included in the {@code request}.
-     * Visibility settings for a schema type do not apply or persist across {@link
-     * SetSchemaRequest}s.
-     *
-     * <p>Migration: make non-backwards-compatible changes will delete all stored documents in old
-     * schema. You can save your documents by setting {@link
-     * android.app.appsearch.AppSearchSchema.Migrator} via the {@link
-     * SetSchemaRequest.Builder#setMigrator} for each type you want to save.
-     *
-     * <p>{@link android.app.appsearch.AppSearchSchema.Migrator#onDowngrade} or {@link
-     * android.app.appsearch.AppSearchSchema.Migrator#onUpgrade} will be triggered if the version
-     * number of the schema stored in AppSearch is different with the version in the request.
-     *
-     * <p>If any error or Exception occurred in the {@link
-     * android.app.appsearch.AppSearchSchema.Migrator#onDowngrade}, {@link
-     * android.app.appsearch.AppSearchSchema.Migrator#onUpgrade} or {@link
-     * android.app.appsearch.AppSearchMigrationHelper.Transformer#transform}, the migration will be
-     * terminated, the setSchema request will be rejected unless the schema changes are
-     * backwards-compatible, and stored documents won't have any observable changes.
-     *
-     * @param request The schema update request.
-     * @return A {@link ListenableFuture} with exception if we hit any error. Or the pending {@link
-     *     SetSchemaResponse} of performing this operation, if the schema has been successfully set.
-     * @see android.app.appsearch.AppSearchSchema.Migrator
-     * @see android.app.appsearch.AppSearchMigrationHelper.Transformer
+     * @param request the schema to set or update the AppSearch database to.
+     * @return a {@link ListenableFuture} which resolves to a {@link SetSchemaResponse} object.
      */
     // TODO(b/169883602): Change @code references to @link when setPlatformSurfaceable APIs are
     //  exposed.
diff --git a/apex/jobscheduler/framework/java/android/app/AlarmManager.java b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
index 7c7b210..77146e0 100644
--- a/apex/jobscheduler/framework/java/android/app/AlarmManager.java
+++ b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
@@ -23,7 +23,7 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.compat.annotation.ChangeId;
-import android.compat.annotation.Disabled;
+import android.compat.annotation.EnabledSince;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
@@ -202,7 +202,7 @@
      * @hide
      */
     @ChangeId
-    @Disabled // TODO (b/171306433): Enable starting S.
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
     public static final long REQUIRE_EXACT_ALARM_PERMISSION = 171306433L;
 
     @UnsupportedAppUsage
diff --git a/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl b/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl
index 5693abe..43d4873 100644
--- a/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl
+++ b/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl
@@ -43,10 +43,10 @@
     boolean isPowerSaveWhitelistApp(String name);
     @UnsupportedAppUsage(maxTargetSdk = 30,
      publicAlternatives = "Use SystemApi {@code PowerWhitelistManager#whitelistAppTemporarily(String, int, String)}.")
-    void addPowerSaveTempWhitelistApp(String name, long duration, int userId, String reason);
-    long addPowerSaveTempWhitelistAppForMms(String name, int userId, String reason);
-    long addPowerSaveTempWhitelistAppForSms(String name, int userId, String reason);
-    long whitelistAppTemporarily(String name, int userId, String reason);
+    void addPowerSaveTempWhitelistApp(String name, long duration, int userId, int reasonCode, String reason);
+    long addPowerSaveTempWhitelistAppForMms(String name, int userId, int reasonCode, String reason);
+    long addPowerSaveTempWhitelistAppForSms(String name, int userId, int reasonCode, String reason);
+    long whitelistAppTemporarily(String name, int userId, int reasonCode, String reason);
     void exitIdle(String reason);
     int setPreIdleTimeoutMode(int Mode);
     void resetPreIdleTimeoutMode();
diff --git a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
index df0e157..b1b733a 100644
--- a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
+++ b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
@@ -16,8 +16,16 @@
 
 package android.os;
 
+import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
+import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT;
+import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI;
+import static android.app.ActivityManager.PROCESS_STATE_TOP;
+
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
@@ -94,6 +102,258 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface TempAllowListType {}
 
+    /* Reason code for BG-FGS-launch. */
+    /**
+     * BG-FGS-launch is denied.
+     * @hide
+     */
+    public static final int REASON_DENIED = -1;
+
+    /* Reason code range 0-9 are reserved for default reasons */
+    /**
+     * The default reason code if reason is unknown.
+     */
+    public static final int REASON_UNKNOWN = 0;
+    /**
+     * Use REASON_OTHER if there is no better choice.
+     */
+    public static final int REASON_OTHER = 1;
+
+    /* Reason code range 10-49 are reserved for BG-FGS-launch allowed proc states */
+    /** @hide */
+    public static final int REASON_PROC_STATE_PERSISTENT = 10;
+    /** @hide */
+    public static final int REASON_PROC_STATE_PERSISTENT_UI = 11;
+    /** @hide */
+    public static final int REASON_PROC_STATE_TOP = 12;
+    /** @hide */
+    public static final int REASON_PROC_STATE_BTOP = 13;
+    /** @hide */
+    public static final int REASON_PROC_STATE_FGS = 14;
+    /** @hide */
+    public static final int REASON_PROC_STATE_BFGS = 15;
+
+    /* Reason code range 50-99 are reserved for BG-FGS-launch allowed reasons */
+    /** @hide */
+    public static final int REASON_UID_VISIBLE = 50;
+    /** @hide */
+    public static final int REASON_SYSTEM_UID = 51;
+    /** @hide */
+    public static final int REASON_ACTIVITY_STARTER = 52;
+    /** @hide */
+    public static final int REASON_START_ACTIVITY_FLAG = 53;
+    /** @hide */
+    public static final int REASON_FGS_BINDING = 54;
+    /** @hide */
+    public static final int REASON_DEVICE_OWNER = 55;
+    /** @hide */
+    public static final int REASON_PROFILE_OWNER = 56;
+    /** @hide */
+    public static final int REASON_COMPANION_DEVICE_MANAGER = 57;
+    /**
+     * START_ACTIVITIES_FROM_BACKGROUND permission.
+     * @hide
+     */
+    public static final int REASON_BACKGROUND_ACTIVITY_PERMISSION = 58;
+    /**
+     * START_FOREGROUND_SERVICES_FROM_BACKGROUND permission.
+     * @hide
+     */
+    public static final int REASON_BACKGROUND_FGS_PERMISSION = 59;
+    /** @hide */
+    public static final int REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION = 60;
+    /** @hide */
+    public static final int REASON_INSTR_BACKGROUND_FGS_PERMISSION = 61;
+    /** @hide */
+    public static final int REASON_SYSTEM_ALERT_WINDOW_PERMISSION = 62;
+    /** @hide */
+    public static final int REASON_DEVICE_DEMO_MODE = 63;
+    /** @hide */
+    public static final int REASON_EXEMPTED_PACKAGE = 64;
+    /** @hide */
+    public static final int REASON_ALLOWLISTED_PACKAGE  = 65;
+    /** @hide */
+    public static final int REASON_APPOP = 66;
+
+    /* BG-FGS-launch is allowed by temp-allowlist or system-allowlist.
+       Reason code for temp and system allowlist starts here.
+       Reason code range 100-199 are reserved for public reasons. */
+    /**
+     * Set temp-allowlist for location geofence purpose.
+     */
+    public static final int REASON_GEOFENCING = 100;
+    /**
+     * Set temp-allowlist for server push messaging.
+     */
+    public static final int REASON_PUSH_MESSAGING = 101;
+    /**
+     * Set temp-allowlist for server push messaging over the quota.
+     */
+    public static final int REASON_PUSH_MESSAGING_OVER_QUOTA = 102;
+    /**
+     * Set temp-allowlist for activity recognition.
+     */
+    public static final int REASON_ACTIVITY_RECOGNITION = 103;
+
+    /* Reason code range 200-299 are reserved for broadcast actions */
+    /**
+     * Broadcast ACTION_BOOT_COMPLETED.
+     * @hide
+     */
+    public static final int REASON_BOOT_COMPLETED = 200;
+    /**
+     * Broadcast ACTION_PRE_BOOT_COMPLETED.
+     * @hide
+     */
+    public static final int REASON_PRE_BOOT_COMPLETED = 201;
+    /**
+     * Broadcast ACTION_LOCKED_BOOT_COMPLETED.
+     * @hide
+     */
+    public static final int REASON_LOCKED_BOOT_COMPLETED = 202;
+
+    /* Reason code range 300-399 are reserved for other internal reasons */
+    /**
+     * Device idle system allowlist, including EXCEPT-IDLE
+     * @hide
+     */
+    public static final int REASON_SYSTEM_ALLOW_LISTED  = 300;
+    /** @hide */
+    public static final int REASON_ALARM_MANAGER_ALARM_CLOCK = 301;
+    /**
+     * AlarmManagerService.
+     * @hide
+     */
+    public static final int REASON_ALARM_MANAGER_WHILE_IDLE = 302;
+    /**
+     * ActiveServices.
+     * @hide
+     */
+    public static final int REASON_SERVICE_LAUNCH = 303;
+    /**
+     * KeyChainSystemService.
+     * @hide
+     */
+    public static final int REASON_KEY_CHAIN = 304;
+    /**
+     * PackageManagerService.
+     * @hide
+     */
+    public static final int REASON_PACKAGE_VERIFIER = 305;
+    /**
+     * SyncManager.
+     * @hide
+     */
+    public static final int REASON_SYNC_MANAGER = 306;
+    /**
+     * DomainVerificationProxyV1.
+     * @hide
+     */
+    public static final int REASON_DOMAIN_VERIFICATION_V1 = 307;
+    /**
+     * DomainVerificationProxyV2.
+     * @hide
+     */
+    public static final int REASON_DOMAIN_VERIFICATION_V2 = 308;
+    /** @hide */
+    public static final int REASON_VPN = 309;
+    /**
+     * NotificationManagerService.
+     * @hide
+     */
+    public static final int REASON_NOTIFICATION_SERVICE = 310;
+    /**
+     * Broadcast ACTION_MY_PACKAGE_REPLACED.
+     * @hide
+     */
+    public static final int REASON_PACKAGE_REPLACED = 311;
+    /**
+     * LocationProviderManager.
+     * @hide
+     */
+    public static final int REASON_LOCATION_PROVIDER = 312;
+    /**
+     * MediaButtonReceiver.
+     * @hide
+     */
+    public static final int REASON_MEDIA_BUTTON = 313;
+    /**
+     * InboundSmsHandler.
+     * @hide
+     */
+    public static final int REASON_EVENT_SMS = 314;
+    /**
+     * InboundSmsHandler.
+     * @hide
+     */
+    public static final int REASON_EVENT_MMS = 315;
+    /**
+     * Shell app.
+     * @hide
+     */
+    public static final int REASON_SHELL = 316;
+
+    /**
+     * The list of BG-FGS-Launch and temp-allowlist reason code.
+     * @hide
+     */
+    @IntDef(flag = true, prefix = { "REASON_" }, value = {
+            // BG-FGS-Launch reasons.
+            REASON_DENIED,
+            REASON_UNKNOWN,
+            REASON_OTHER,
+            REASON_PROC_STATE_PERSISTENT,
+            REASON_PROC_STATE_PERSISTENT_UI,
+            REASON_PROC_STATE_TOP,
+            REASON_PROC_STATE_BTOP,
+            REASON_PROC_STATE_FGS,
+            REASON_PROC_STATE_BFGS,
+            REASON_UID_VISIBLE,
+            REASON_SYSTEM_UID,
+            REASON_ACTIVITY_STARTER,
+            REASON_START_ACTIVITY_FLAG,
+            REASON_FGS_BINDING,
+            REASON_DEVICE_OWNER,
+            REASON_PROFILE_OWNER,
+            REASON_COMPANION_DEVICE_MANAGER,
+            REASON_BACKGROUND_ACTIVITY_PERMISSION,
+            REASON_BACKGROUND_FGS_PERMISSION,
+            REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION,
+            REASON_INSTR_BACKGROUND_FGS_PERMISSION,
+            REASON_SYSTEM_ALERT_WINDOW_PERMISSION,
+            REASON_DEVICE_DEMO_MODE,
+            REASON_EXEMPTED_PACKAGE,
+            REASON_ALLOWLISTED_PACKAGE,
+            REASON_APPOP,
+            // temp and system allowlist reasons.
+            REASON_GEOFENCING,
+            REASON_PUSH_MESSAGING,
+            REASON_PUSH_MESSAGING_OVER_QUOTA,
+            REASON_ACTIVITY_RECOGNITION,
+            REASON_BOOT_COMPLETED,
+            REASON_PRE_BOOT_COMPLETED,
+            REASON_LOCKED_BOOT_COMPLETED,
+            REASON_SYSTEM_ALLOW_LISTED,
+            REASON_ALARM_MANAGER_ALARM_CLOCK,
+            REASON_ALARM_MANAGER_WHILE_IDLE,
+            REASON_SERVICE_LAUNCH,
+            REASON_KEY_CHAIN,
+            REASON_PACKAGE_VERIFIER,
+            REASON_SYNC_MANAGER,
+            REASON_DOMAIN_VERIFICATION_V1,
+            REASON_DOMAIN_VERIFICATION_V2,
+            REASON_VPN,
+            REASON_NOTIFICATION_SERVICE,
+            REASON_PACKAGE_REPLACED,
+            REASON_LOCATION_PROVIDER,
+            REASON_MEDIA_BUTTON,
+            REASON_EVENT_SMS,
+            REASON_EVENT_MMS,
+            REASON_SHELL,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ReasonCode {}
+
     /**
      * @hide
      */
@@ -184,19 +444,34 @@
      *
      * @param packageName The package to add to the temp whitelist
      * @param durationMs  How long to keep the app on the temp whitelist for (in milliseconds)
+     * @param reasonCode one of {@link ReasonCode}, use {@link #REASON_UNKNOWN} if not sure.
+     * @param reason a optional human readable reason string, could be null or empty string.
      */
     @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
-    public void whitelistAppTemporarily(@NonNull String packageName, long durationMs) {
-        String reason = "from:" + UserHandle.formatUid(Binder.getCallingUid());
+    public void whitelistAppTemporarily(@NonNull String packageName, long durationMs,
+            @ReasonCode int reasonCode, @Nullable String reason) {
         try {
             mService.addPowerSaveTempWhitelistApp(packageName, durationMs, mContext.getUserId(),
-                    reason);
+                    reasonCode, reason);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
+     * Add an app to the temporary whitelist for a short amount of time.
+     *
+     * @param packageName The package to add to the temp whitelist
+     * @param durationMs  How long to keep the app on the temp whitelist for (in milliseconds)
+     * @deprecated Use {@link #whitelistAppTemporarily(String, long, int, String)} instead
+     */
+    @Deprecated
+    @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
+    public void whitelistAppTemporarily(@NonNull String packageName, long durationMs) {
+        whitelistAppTemporarily(packageName, durationMs, REASON_UNKNOWN, packageName);
+    }
+
+    /**
      * Add an app to the temporary whitelist for a short amount of time for a specific reason. The
      * temporary whitelist is kept separately from the permanent whitelist and apps are
      * automatically removed from the temporary whitelist after a predetermined amount of time.
@@ -204,27 +479,181 @@
      * @param packageName The package to add to the temp whitelist
      * @param event       The reason to add the app to the temp whitelist
      * @param reason      A human-readable reason explaining why the app is temp whitelisted. Only
-     *                    used for logging purposes
+     *                    used for logging purposes. Could be null or empty string.
+     * @return The duration (in milliseconds) that the app is whitelisted for
+     * @deprecated Use {@link #whitelistAppTemporarilyForEvent(String, int, int, String)} instead
+     */
+    @Deprecated
+    @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
+    public long whitelistAppTemporarilyForEvent(@NonNull String packageName,
+            @WhitelistEvent int event, @Nullable String reason) {
+        return whitelistAppTemporarilyForEvent(packageName, event, REASON_UNKNOWN, reason);
+    }
+
+    /**
+     * Add an app to the temporary whitelist for a short amount of time for a specific reason. The
+     * temporary whitelist is kept separately from the permanent whitelist and apps are
+     * automatically removed from the temporary whitelist after a predetermined amount of time.
+     *
+     * @param packageName The package to add to the temp whitelist
+     * @param event       The reason to add the app to the temp whitelist
+     * @param reasonCode  one of {@link ReasonCode}, use {@link #REASON_UNKNOWN} if not sure.
+     * @param reason      A human-readable reason explaining why the app is temp whitelisted. Only
+     *                    used for logging purposes. Could be null or empty string.
      * @return The duration (in milliseconds) that the app is whitelisted for
      */
     @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
     public long whitelistAppTemporarilyForEvent(@NonNull String packageName,
-            @WhitelistEvent int event, @NonNull String reason) {
+            @WhitelistEvent int event, @ReasonCode int reasonCode, @Nullable String reason) {
         try {
             switch (event) {
                 case EVENT_MMS:
                     return mService.addPowerSaveTempWhitelistAppForMms(
-                            packageName, mContext.getUserId(), reason);
+                            packageName, mContext.getUserId(), reasonCode, reason);
                 case EVENT_SMS:
                     return mService.addPowerSaveTempWhitelistAppForSms(
-                            packageName, mContext.getUserId(), reason);
+                            packageName, mContext.getUserId(), reasonCode, reason);
                 case EVENT_UNSPECIFIED:
                 default:
                     return mService.whitelistAppTemporarily(
-                            packageName, mContext.getUserId(), reason);
+                            packageName, mContext.getUserId(), reasonCode, reason);
             }
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * @hide
+     */
+    public static @ReasonCode int getReasonCodeFromProcState(int procState) {
+        if (procState <= PROCESS_STATE_PERSISTENT) {
+            return REASON_PROC_STATE_PERSISTENT;
+        } else if (procState <= PROCESS_STATE_PERSISTENT_UI) {
+            return REASON_PROC_STATE_PERSISTENT_UI;
+        } else if (procState <= PROCESS_STATE_TOP) {
+            return REASON_PROC_STATE_TOP;
+        } else if (procState <= PROCESS_STATE_BOUND_TOP) {
+            return REASON_PROC_STATE_BTOP;
+        } else if (procState <= PROCESS_STATE_FOREGROUND_SERVICE) {
+            return REASON_PROC_STATE_FGS;
+        } else if (procState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
+            return REASON_PROC_STATE_BFGS;
+        } else {
+            return REASON_DENIED;
+        }
+    }
+
+    /**
+     * Return string name of the integer reason code.
+     * @hide
+     * @param reasonCode
+     * @return string name of the reason code.
+     */
+    public static String reasonCodeToString(@ReasonCode int reasonCode) {
+        switch (reasonCode) {
+            case REASON_DENIED:
+                return "DENIED";
+            case REASON_UNKNOWN:
+                return "UNKNOWN";
+            case REASON_OTHER:
+                return "OTHER";
+            case REASON_PROC_STATE_PERSISTENT:
+                return "PROC_STATE_PERSISTENT";
+            case REASON_PROC_STATE_PERSISTENT_UI:
+                return "PROC_STATE_PERSISTENT_UI";
+            case REASON_PROC_STATE_TOP:
+                return "PROC_STATE_TOP";
+            case REASON_PROC_STATE_BTOP:
+                return "PROC_STATE_BTOP";
+            case REASON_PROC_STATE_FGS:
+                return "PROC_STATE_FGS";
+            case REASON_PROC_STATE_BFGS:
+                return "PROC_STATE_BFGS";
+            case REASON_UID_VISIBLE:
+                return "UID_VISIBLE";
+            case REASON_SYSTEM_UID:
+                return "SYSTEM_UID";
+            case REASON_ACTIVITY_STARTER:
+                return "ACTIVITY_STARTER";
+            case REASON_START_ACTIVITY_FLAG:
+                return "START_ACTIVITY_FLAG";
+            case REASON_FGS_BINDING:
+                return "FGS_BINDING";
+            case REASON_DEVICE_OWNER:
+                return "DEVICE_OWNER";
+            case REASON_PROFILE_OWNER:
+                return "PROFILE_OWNER";
+            case REASON_COMPANION_DEVICE_MANAGER:
+                return "COMPANION_DEVICE_MANAGER";
+            case REASON_BACKGROUND_ACTIVITY_PERMISSION:
+                return "BACKGROUND_ACTIVITY_PERMISSION";
+            case REASON_BACKGROUND_FGS_PERMISSION:
+                return "BACKGROUND_FGS_PERMISSION";
+            case REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION:
+                return "INSTR_BACKGROUND_ACTIVITY_PERMISSION";
+            case REASON_INSTR_BACKGROUND_FGS_PERMISSION:
+                return "INSTR_BACKGROUND_FGS_PERMISSION";
+            case REASON_SYSTEM_ALERT_WINDOW_PERMISSION:
+                return "SYSTEM_ALERT_WINDOW_PERMISSION";
+            case REASON_DEVICE_DEMO_MODE:
+                return "DEVICE_DEMO_MODE";
+            case REASON_EXEMPTED_PACKAGE:
+                return "EXEMPTED_PACKAGE";
+            case REASON_ALLOWLISTED_PACKAGE:
+                return "ALLOWLISTED_PACKAGE";
+            case REASON_APPOP:
+                return "APPOP";
+            case REASON_GEOFENCING:
+                return "GEOFENCING";
+            case REASON_PUSH_MESSAGING:
+                return "PUSH_MESSAGING";
+            case REASON_PUSH_MESSAGING_OVER_QUOTA:
+                return "PUSH_MESSAGING_OVER_QUOTA";
+            case REASON_ACTIVITY_RECOGNITION:
+                return "ACTIVITY_RECOGNITION";
+            case REASON_BOOT_COMPLETED:
+                return "BOOT_COMPLETED";
+            case REASON_PRE_BOOT_COMPLETED:
+                return "PRE_BOOT_COMPLETED";
+            case REASON_LOCKED_BOOT_COMPLETED:
+                return "LOCKED_BOOT_COMPLETED";
+            case REASON_SYSTEM_ALLOW_LISTED:
+                return "SYSTEM_ALLOW_LISTED";
+            case REASON_ALARM_MANAGER_ALARM_CLOCK:
+                return "ALARM_MANAGER_ALARM_CLOCK";
+            case REASON_ALARM_MANAGER_WHILE_IDLE:
+                return "ALARM_MANAGER_WHILE_IDLE";
+            case REASON_SERVICE_LAUNCH:
+                return "SERVICE_LAUNCH";
+            case REASON_KEY_CHAIN:
+                return "KEY_CHAIN";
+            case REASON_PACKAGE_VERIFIER:
+                return "PACKAGE_VERIFIER";
+            case REASON_SYNC_MANAGER:
+                return "SYNC_MANAGER";
+            case REASON_DOMAIN_VERIFICATION_V1:
+                return "DOMAIN_VERIFICATION_V1";
+            case REASON_DOMAIN_VERIFICATION_V2:
+                return "DOMAIN_VERIFICATION_V2";
+            case REASON_VPN:
+                return "VPN";
+            case REASON_NOTIFICATION_SERVICE:
+                return "NOTIFICATION_SERVICE";
+            case REASON_PACKAGE_REPLACED:
+                return "PACKAGE_REPLACED";
+            case REASON_LOCATION_PROVIDER:
+                return "LOCATION_PROVIDER";
+            case REASON_MEDIA_BUTTON:
+                return "MEDIA_BUTTON";
+            case REASON_EVENT_SMS:
+                return "EVENT_SMS";
+            case REASON_EVENT_MMS:
+                return "EVENT_MMS";
+            case REASON_SHELL:
+                return "SHELL";
+            default:
+                return  "(unknown:" + reasonCode + ")";
+        }
+    }
 }
diff --git a/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java b/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java
index e045b0f..5e5717d11 100644
--- a/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java
@@ -16,6 +16,8 @@
 
 package com.android.server;
 
+import android.annotation.Nullable;
+import android.os.PowerWhitelistManager.ReasonCode;
 import android.os.PowerWhitelistManager.TempAllowListType;
 
 import com.android.server.deviceidle.IDeviceIdleConstraint;
@@ -34,6 +36,10 @@
     void addPowerSaveTempWhitelistApp(int callingUid, String packageName,
             long duration, int userId, boolean sync, String reason);
 
+    void addPowerSaveTempWhitelistApp(int callingUid, String packageName,
+            long duration, int userId, boolean sync, @ReasonCode int reasonCode,
+            @Nullable String reason);
+
     /**
      * Called by ActivityManagerService to directly add UID to DeviceIdleController's temp
      * allowlist.
@@ -41,11 +47,12 @@
      * @param duration duration in milliseconds
      * @param type temp allowlist type defined at {@link TempAllowListType}
      * @param sync
+     * @param reasonCode one of {@link ReasonCode}
      * @param reason
      */
     void addPowerSaveTempWhitelistAppDirect(int uid, long duration,
-            @TempAllowListType int type, boolean sync,
-            String reason);
+            @TempAllowListType int type, boolean sync, @ReasonCode int reasonCode,
+            @Nullable String reason);
 
     // duration in milliseconds
     long getNotificationAllowlistDuration();
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 8f7f705..ac28e82 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -16,12 +16,17 @@
 
 package com.android.server;
 
+import static android.os.PowerWhitelistManager.REASON_SHELL;
+import static android.os.PowerWhitelistManager.REASON_UNKNOWN;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
+import static android.os.Process.INVALID_UID;
+
 import android.Manifest;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
-import android.app.BroadcastOptions;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -56,6 +61,7 @@
 import android.os.PowerManager;
 import android.os.PowerManager.ServiceType;
 import android.os.PowerManagerInternal;
+import android.os.PowerWhitelistManager.ReasonCode;
 import android.os.PowerWhitelistManager.TempAllowListType;
 import android.os.Process;
 import android.os.RemoteException;
@@ -1838,31 +1844,34 @@
         }
 
         @Override
-        public long whitelistAppTemporarily(String packageName, int userId, String reason)
-                throws RemoteException {
+        public long whitelistAppTemporarily(String packageName, int userId,
+                @ReasonCode int reasonCode, @Nullable String reason) throws RemoteException {
             // At least 10 seconds.
             long durationMs = Math.max(10_000L, mConstants.MAX_TEMP_APP_ALLOWLIST_DURATION_MS / 2);
-            addPowerSaveTempAllowlistAppChecked(packageName, durationMs, userId, reason);
+            addPowerSaveTempAllowlistAppChecked(packageName, durationMs, userId, reasonCode,
+                    reason);
             return durationMs;
         }
 
         @Override
-        public void addPowerSaveTempWhitelistApp(String packageName, long duration,
-                int userId, String reason) throws RemoteException {
-            addPowerSaveTempAllowlistAppChecked(packageName, duration, userId, reason);
+        public void addPowerSaveTempWhitelistApp(String packageName, long duration, int userId,
+                @ReasonCode int reasonCode, @Nullable String reason) throws RemoteException {
+            addPowerSaveTempAllowlistAppChecked(packageName, duration, userId, reasonCode, reason);
         }
 
-        @Override public long addPowerSaveTempWhitelistAppForMms(String packageName,
-                int userId, String reason) throws RemoteException {
+        @Override public long addPowerSaveTempWhitelistAppForMms(String packageName, int userId,
+                @ReasonCode int reasonCode, @Nullable String reason) throws RemoteException {
             long durationMs = mConstants.MMS_TEMP_APP_ALLOWLIST_DURATION_MS;
-            addPowerSaveTempAllowlistAppChecked(packageName, durationMs, userId, reason);
+            addPowerSaveTempAllowlistAppChecked(packageName, durationMs, userId, reasonCode,
+                    reason);
             return durationMs;
         }
 
-        @Override public long addPowerSaveTempWhitelistAppForSms(String packageName,
-                int userId, String reason) throws RemoteException {
+        @Override public long addPowerSaveTempWhitelistAppForSms(String packageName, int userId,
+                @ReasonCode int reasonCode, @Nullable String reason) throws RemoteException {
             long durationMs = mConstants.SMS_TEMP_APP_ALLOWLIST_DURATION_MS;
-            addPowerSaveTempAllowlistAppChecked(packageName, durationMs, userId, reason);
+            addPowerSaveTempAllowlistAppChecked(packageName, durationMs, userId, reasonCode,
+                    reason);
             return durationMs;
         }
 
@@ -1934,18 +1943,29 @@
         }
 
         // duration in milliseconds
+        @Deprecated
         @Override
         public void addPowerSaveTempWhitelistApp(int callingUid, String packageName,
-                long duration, int userId, boolean sync, String reason) {
+                long duration, int userId, boolean sync, @Nullable String reason) {
             addPowerSaveTempAllowlistAppInternal(callingUid, packageName, duration,
-                    userId, sync, reason);
+                    userId, sync, REASON_UNKNOWN, reason);
+        }
+
+        @Override
+        public void addPowerSaveTempWhitelistApp(int callingUid, String packageName,
+                long duration, int userId, boolean sync, @ReasonCode int reasonCode,
+                @Nullable String reason) {
+            addPowerSaveTempAllowlistAppInternal(callingUid, packageName, duration,
+                    userId, sync, reasonCode, reason);
         }
 
         // duration in milliseconds
         @Override
         public void addPowerSaveTempWhitelistAppDirect(int uid, long duration,
-                @TempAllowListType int type, boolean sync, String reason) {
-            addPowerSaveTempWhitelistAppDirectInternal(0, uid, duration, type, sync, reason);
+                @TempAllowListType int type, boolean sync, @ReasonCode int reasonCode,
+                @Nullable String reason) {
+            addPowerSaveTempWhitelistAppDirectInternal(0, uid, duration, type, sync,
+                    reasonCode, reason);
         }
 
         // duration in milliseconds
@@ -2293,7 +2313,7 @@
                 filter.addAction(Intent.ACTION_SCREEN_ON);
                 getContext().registerReceiver(mInteractivityReceiver, filter);
 
-                mLocalActivityManager.setDeviceIdleWhitelist(
+                mLocalActivityManager.setDeviceIdleAllowlist(
                         mPowerSaveWhitelistAllAppIdArray, mPowerSaveWhitelistExceptIdleAppIdArray);
                 mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
 
@@ -2671,7 +2691,8 @@
     }
 
     void addPowerSaveTempAllowlistAppChecked(String packageName, long duration,
-            int userId, String reason) throws RemoteException {
+            int userId, @ReasonCode int reasonCode, @Nullable String reason)
+            throws RemoteException {
         getContext().enforceCallingPermission(
                 Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
                 "No permission to change device idle whitelist");
@@ -2686,7 +2707,7 @@
         final long token = Binder.clearCallingIdentity();
         try {
             addPowerSaveTempAllowlistAppInternal(callingUid,
-                    packageName, duration, userId, true, reason);
+                    packageName, duration, userId, true, reasonCode, reason);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -2718,12 +2739,12 @@
      * app an exemption to access network and acquire wakelocks.
      */
     void addPowerSaveTempAllowlistAppInternal(int callingUid, String packageName,
-            long duration, int userId, boolean sync, String reason) {
+            long duration, int userId, boolean sync, @ReasonCode int reasonCode,
+            @Nullable String reason) {
         try {
             int uid = getContext().getPackageManager().getPackageUidAsUser(packageName, userId);
             addPowerSaveTempWhitelistAppDirectInternal(callingUid, uid, duration,
-                    BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED, sync,
-                    reason);
+                    TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, sync, reasonCode, reason);
         } catch (NameNotFoundException e) {
         }
     }
@@ -2733,7 +2754,8 @@
      * app an exemption to access network and acquire wakelocks.
      */
     void addPowerSaveTempWhitelistAppDirectInternal(int callingUid, int uid,
-            long duration, @TempAllowListType int type, boolean sync, String reason) {
+            long duration, @TempAllowListType int type, boolean sync, @ReasonCode int reasonCode,
+            @Nullable String reason) {
         final long timeNow = SystemClock.elapsedRealtime();
         boolean informWhitelistChanged = false;
         int appId = UserHandle.getAppId(uid);
@@ -2765,7 +2787,8 @@
                 } catch (RemoteException e) {
                 }
                 postTempActiveTimeoutMessage(uid, duration);
-                updateTempWhitelistAppIdsLocked(uid, true, duration, type);
+                updateTempWhitelistAppIdsLocked(uid, true, duration, type, reasonCode,
+                        reason, callingUid);
                 if (sync) {
                     informWhitelistChanged = true;
                 } else {
@@ -2844,12 +2867,13 @@
     }
 
     @GuardedBy("this")
-    private void onAppRemovedFromTempWhitelistLocked(int uid, String reason) {
+    private void onAppRemovedFromTempWhitelistLocked(int uid, @Nullable String reason) {
         if (DEBUG) {
             Slog.d(TAG, "Removing uid " + uid + " from temp whitelist");
         }
         final int appId = UserHandle.getAppId(uid);
-        updateTempWhitelistAppIdsLocked(uid, false, 0, 0);
+        updateTempWhitelistAppIdsLocked(uid, false, 0, 0, REASON_UNKNOWN,
+                reason, INVALID_UID);
         mHandler.obtainMessage(MSG_REPORT_TEMP_APP_WHITELIST_CHANGED_TO_NPMS, appId, 0)
                 .sendToTarget();
         reportTempWhitelistChangedLocked(uid, false);
@@ -3860,7 +3884,7 @@
         mPowerSaveWhitelistUserAppIdArray = buildAppIdArray(null,
                 mPowerSaveWhitelistUserApps, mPowerSaveWhitelistUserAppIds);
         if (mLocalActivityManager != null) {
-            mLocalActivityManager.setDeviceIdleWhitelist(
+            mLocalActivityManager.setDeviceIdleAllowlist(
                     mPowerSaveWhitelistAllAppIdArray, mPowerSaveWhitelistExceptIdleAppIdArray);
         }
         if (mLocalPowerManager != null) {
@@ -3880,9 +3904,14 @@
      * @param durationMs duration in milliseconds to add to temp allowlist, only valid when
      *                   param adding is true.
      * @param type temp allowlist type defined at {@link TempAllowListType}
+     * @prama reasonCode one of {@Link ReasonCode}
+     * @param reason A human-readable reason for logging purposes.
+     * @param callingUid the callingUid that setup this temp-allowlist, only valid when param adding
+     *                   is true.
      */
     private void updateTempWhitelistAppIdsLocked(int uid, boolean adding, long durationMs,
-            @TempAllowListType int type) {
+            @TempAllowListType int type, @ReasonCode int reasonCode, @Nullable String reason,
+            int callingUid) {
         final int size = mTempWhitelistAppIdEndTimes.size();
         if (mTempWhitelistAppIdArray.length != size) {
             mTempWhitelistAppIdArray = new int[size];
@@ -3895,8 +3924,8 @@
                 Slog.d(TAG, "Setting activity manager temp whitelist to "
                         + Arrays.toString(mTempWhitelistAppIdArray));
             }
-            mLocalActivityManager.updateDeviceIdleTempWhitelist(mTempWhitelistAppIdArray, uid,
-                    adding, durationMs, type);
+            mLocalActivityManager.updateDeviceIdleTempAllowlist(mTempWhitelistAppIdArray, uid,
+                    adding, durationMs, type, reasonCode, reason, callingUid);
         }
         if (mLocalPowerManager != null) {
             if (DEBUG) {
@@ -4428,7 +4457,8 @@
                     if (removePkg) {
                         removePowerSaveTempAllowlistAppChecked(arg, shell.userId);
                     } else {
-                        addPowerSaveTempAllowlistAppChecked(arg, duration, shell.userId, "shell");
+                        addPowerSaveTempAllowlistAppChecked(arg, duration, shell.userId,
+                                REASON_SHELL, "shell");
                     }
                 } catch (Exception e) {
                     pw.println("Failed: " + e);
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 559a434..2b2918c 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -28,6 +28,8 @@
 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.PowerWhitelistManager.REASON_ALARM_MANAGER_WHILE_IDLE;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
 import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED;
 import static android.os.UserHandle.USER_SYSTEM;
 
@@ -423,6 +425,8 @@
         static final String KEY_ALLOW_WHILE_IDLE_COMPAT_QUOTA = "allow_while_idle_compat_quota";
         private static final String KEY_ALLOW_WHILE_IDLE_WINDOW = "allow_while_idle_window";
 
+        private static final String KEY_CRASH_NON_CLOCK_APPS = "crash_non_clock_apps";
+
         private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
         private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
         private static final long DEFAULT_MAX_INTERVAL = 365 * DateUtils.DAY_IN_MILLIS;
@@ -454,6 +458,8 @@
         private static final int DEFAULT_ALLOW_WHILE_IDLE_QUOTA = 72;
 
         private static final long DEFAULT_ALLOW_WHILE_IDLE_WINDOW = 60 * 60 * 1000; // 1 hour.
+        // TODO (b/171306433): Change to true by default.
+        private static final boolean DEFAULT_CRASH_NON_CLOCK_APPS = false;
 
         // Minimum futurity of a new alarm
         public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY;
@@ -495,6 +501,13 @@
          */
         public long ALLOW_WHILE_IDLE_WINDOW = DEFAULT_ALLOW_WHILE_IDLE_WINDOW;
 
+        /**
+         * Whether or not to crash callers that use setExactAndAllowWhileIdle or setAlarmClock
+         * but don't hold the required permission. This is useful to catch broken
+         * apps and reverting to a softer failure in case of broken apps.
+         */
+        public boolean CRASH_NON_CLOCK_APPS = DEFAULT_CRASH_NON_CLOCK_APPS;
+
         private long mLastAllowWhileIdleWhitelistDuration = -1;
 
         Constants() {
@@ -513,10 +526,12 @@
             if (mLastAllowWhileIdleWhitelistDuration != ALLOW_WHILE_IDLE_WHITELIST_DURATION) {
                 mLastAllowWhileIdleWhitelistDuration = ALLOW_WHILE_IDLE_WHITELIST_DURATION;
 
-                mOptsWithFgs.setTemporaryAppWhitelistDuration(ALLOW_WHILE_IDLE_WHITELIST_DURATION);
-                mOptsWithoutFgs.setTemporaryAppWhitelistDuration(
+                mOptsWithFgs.setTemporaryAppAllowlist(ALLOW_WHILE_IDLE_WHITELIST_DURATION,
+                        TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                        REASON_ALARM_MANAGER_WHILE_IDLE, "");
+                mOptsWithoutFgs.setTemporaryAppAllowlist(ALLOW_WHILE_IDLE_WHITELIST_DURATION,
                         TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED,
-                        ALLOW_WHILE_IDLE_WHITELIST_DURATION);
+                        REASON_ALARM_MANAGER_WHILE_IDLE, "");
             }
         }
 
@@ -607,6 +622,10 @@
                                     KEY_TIME_TICK_ALLOWED_WHILE_IDLE,
                                     DEFAULT_TIME_TICK_ALLOWED_WHILE_IDLE);
                             break;
+                        case KEY_CRASH_NON_CLOCK_APPS:
+                            CRASH_NON_CLOCK_APPS = properties.getBoolean(KEY_CRASH_NON_CLOCK_APPS,
+                                    DEFAULT_CRASH_NON_CLOCK_APPS);
+                            break;
                         default:
                             if (name.startsWith(KEY_PREFIX_STANDBY_QUOTA) && !standbyQuotaUpdated) {
                                 // The quotas need to be updated in order, so we can't just rely
@@ -741,6 +760,9 @@
             pw.print(KEY_TIME_TICK_ALLOWED_WHILE_IDLE, TIME_TICK_ALLOWED_WHILE_IDLE);
             pw.println();
 
+            pw.print(KEY_CRASH_NON_CLOCK_APPS, CRASH_NON_CLOCK_APPS);
+            pw.println();
+
             pw.decreaseIndent();
         }
 
@@ -1914,11 +1936,12 @@
     }
 
     /**
-     * Returns true if the given uid is on the system or user's power save exclusion list.
+     * Returns true if the given uid does not require SCHEDULE_EXACT_ALARM to set exact,
+     * allow-while-idle alarms.
      */
-    boolean isWhitelisted(int uid) {
-        return (mLocalDeviceIdleController == null || mLocalDeviceIdleController.isAppOnWhitelist(
-                UserHandle.getAppId(uid)));
+    boolean isExemptFromPermission(int uid) {
+        return (UserHandle.isSameApp(mSystemUiUid, uid) || mLocalDeviceIdleController == null
+                || mLocalDeviceIdleController.isAppOnWhitelist(UserHandle.getAppId(uid)));
     }
 
     /**
@@ -1949,7 +1972,7 @@
                     if (windowLength != AlarmManager.WINDOW_EXACT) {
                         needsPermission = false;
                         lowQuota = true;
-                        idleOptions = isWhitelisted(callingUid) ? mOptsWithFgs.toBundle()
+                        idleOptions = isExemptFromPermission(callingUid) ? mOptsWithFgs.toBundle()
                                 : mOptsWithoutFgs.toBundle();
                     } else if (alarmClock != null) {
                         needsPermission = true;
@@ -1966,16 +1989,22 @@
                     idleOptions = allowWhileIdle ? mOptsWithFgs.toBundle() : null;
                 }
                 if (needsPermission && !canScheduleExactAlarms()) {
-                    if (alarmClock == null && isWhitelisted(callingUid)) {
+                    if (alarmClock == null && isExemptFromPermission(callingUid)) {
                         // If the app is on the full system allow-list (not except-idle), we still
                         // allow the alarms, but with a lower quota to keep pre-S compatibility.
                         lowQuota = true;
                     } else {
-                        final String errorMessage = "Caller needs to hold "
+                        final String errorMessage = "Caller " + callingPackage + " needs to hold "
                                 + Manifest.permission.SCHEDULE_EXACT_ALARM + " to set "
                                 + ((allowWhileIdle) ? "exact, allow-while-idle" : "alarm-clock")
                                 + " alarms.";
-                        throw new SecurityException(errorMessage);
+                        if (mConstants.CRASH_NON_CLOCK_APPS) {
+                            throw new SecurityException(errorMessage);
+                        } else {
+                            Slog.wtf(TAG, errorMessage);
+                            idleOptions = mOptsWithoutFgs.toBundle();
+                            lowQuota = allowWhileIdle;
+                        }
                     }
                 }
                 if (lowQuota) {
@@ -2933,7 +2962,7 @@
         if (UserHandle.isCore(uid) || uid == mSystemUiUid) {
             return;
         }
-        if (isWhitelisted(uid)) {
+        if (isExemptFromPermission(uid)) {
             return;
         }
         if (!CompatChanges.isChangeEnabled(
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index af97715..0308d68 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -73,20 +73,48 @@
             CONFIG_KEY_PREFIX_CONCURRENCY + "screen_off_adjustment_delay_ms";
     private static final long DEFAULT_SCREEN_OFF_ADJUSTMENT_DELAY_MS = 30_000;
 
-    // Try to give higher priority types lower values.
+    /**
+     * Set of possible execution types that a job can have. The actual type(s) of a job are based
+     * on the {@link JobStatus#lastEvaluatedPriority}, which is typically evaluated right before
+     * execution (when we're trying to determine which jobs to run next) and won't change after the
+     * job has started executing.
+     *
+     * Try to give higher priority types lower values.
+     *
+     * @see #getJobWorkTypes(JobStatus)
+     */
+
+    /** Job shouldn't run or qualify as any other work type. */
     static final int WORK_TYPE_NONE = 0;
+    /** The job is for an app in the TOP state for a currently active user. */
     static final int WORK_TYPE_TOP = 1 << 0;
-    static final int WORK_TYPE_EJ = 1 << 1;
-    static final int WORK_TYPE_BG = 1 << 2;
-    static final int WORK_TYPE_BGUSER = 1 << 3;
+    /**
+     * The job is for an app in a {@link ActivityManager#PROCESS_STATE_FOREGROUND_SERVICE} or higher
+     * state (excluding {@link ActivityManager#PROCESS_STATE_TOP} for a currently active user.
+     */
+    static final int WORK_TYPE_FGS = 1 << 1;
+    /** The job is allowed to run as an expedited job for a currently active user. */
+    static final int WORK_TYPE_EJ = 1 << 2;
+    /**
+     * The job does not satisfy any of the conditions for {@link #WORK_TYPE_TOP},
+     * {@link #WORK_TYPE_FGS}, or {@link #WORK_TYPE_EJ}, but is for a currently active user, so
+     * can run as a background job.
+     */
+    static final int WORK_TYPE_BG = 1 << 3;
+    /**
+     * The job does not satisfy any of the conditions for {@link #WORK_TYPE_TOP},
+     * {@link #WORK_TYPE_FGS}, or {@link #WORK_TYPE_EJ}, but is for a completely background user,
+     * so can run as a background user job.
+     */
+    static final int WORK_TYPE_BGUSER = 1 << 4;
     @VisibleForTesting
-    static final int NUM_WORK_TYPES = 4;
-    private static final int ALL_WORK_TYPES =
-            WORK_TYPE_TOP | WORK_TYPE_EJ | WORK_TYPE_BG | WORK_TYPE_BGUSER;
+    static final int NUM_WORK_TYPES = 5;
+    private static final int ALL_WORK_TYPES = (1 << NUM_WORK_TYPES) - 1;
 
     @IntDef(prefix = {"WORK_TYPE_"}, flag = true, value = {
             WORK_TYPE_NONE,
             WORK_TYPE_TOP,
+            WORK_TYPE_FGS,
             WORK_TYPE_EJ,
             WORK_TYPE_BG,
             WORK_TYPE_BGUSER
@@ -95,12 +123,15 @@
     public @interface WorkType {
     }
 
-    private static String workTypeToString(@WorkType int workType) {
+    @VisibleForTesting
+    static String workTypeToString(@WorkType int workType) {
         switch (workType) {
             case WORK_TYPE_NONE:
                 return "NONE";
             case WORK_TYPE_TOP:
                 return "TOP";
+            case WORK_TYPE_FGS:
+                return "FGS";
             case WORK_TYPE_EJ:
                 return "EJ";
             case WORK_TYPE_BG:
@@ -131,58 +162,60 @@
             new WorkConfigLimitsPerMemoryTrimLevel(
                     new WorkTypeConfig("screen_on_normal", 11,
                             // defaultMin
-                            List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_EJ, 3),
-                                    Pair.create(WORK_TYPE_BG, 2)),
+                            List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_FGS, 1),
+                                    Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2)),
                             // defaultMax
                             List.of(Pair.create(WORK_TYPE_BG, 6), Pair.create(WORK_TYPE_BGUSER, 4))
                     ),
                     new WorkTypeConfig("screen_on_moderate", 9,
                             // defaultMin
-                            List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 2),
-                                    Pair.create(WORK_TYPE_BG, 2)),
+                            List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1),
+                                    Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 2)),
                             // defaultMax
                             List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2))
                     ),
                     new WorkTypeConfig("screen_on_low", 6,
                             // defaultMin
-                            List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 1),
-                                    Pair.create(WORK_TYPE_BG, 1)),
+                            List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1),
+                                    Pair.create(WORK_TYPE_EJ, 1)),
                             // defaultMax
                             List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))
                     ),
-                    new WorkTypeConfig("screen_on_critical", 5,
+                    new WorkTypeConfig("screen_on_critical", 6,
                             // defaultMin
-                            List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 1)),
+                            List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1),
+                                    Pair.create(WORK_TYPE_EJ, 1)),
                             // defaultMax
                             List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))
                     )
             );
     private static final WorkConfigLimitsPerMemoryTrimLevel CONFIG_LIMITS_SCREEN_OFF =
             new WorkConfigLimitsPerMemoryTrimLevel(
-                    new WorkTypeConfig("screen_off_normal", 13,
+                    new WorkTypeConfig("screen_off_normal", 15,
                             // defaultMin
-                            List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 3),
-                                    Pair.create(WORK_TYPE_BG, 2)),
+                            List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 2),
+                                    Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2)),
                             // defaultMax
                             List.of(Pair.create(WORK_TYPE_BG, 6), Pair.create(WORK_TYPE_BGUSER, 4))
                     ),
-                    new WorkTypeConfig("screen_off_moderate", 13,
+                    new WorkTypeConfig("screen_off_moderate", 15,
                             // defaultMin
-                            List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_EJ, 3),
-                                    Pair.create(WORK_TYPE_BG, 2)),
+                            List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_FGS, 2),
+                                    Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2)),
                             // defaultMax
                             List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2))
                     ),
-                    new WorkTypeConfig("screen_off_low", 7,
+                    new WorkTypeConfig("screen_off_low", 9,
                             // defaultMin
-                            List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 2),
-                                    Pair.create(WORK_TYPE_BG, 1)),
+                            List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1),
+                                    Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 1)),
                             // defaultMax
                             List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))
                     ),
-                    new WorkTypeConfig("screen_off_critical", 5,
+                    new WorkTypeConfig("screen_off_critical", 6,
                             // defaultMin
-                            List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 1)),
+                            List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1),
+                                    Pair.create(WORK_TYPE_EJ, 1)),
                             // defaultMax
                             List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))
                     )
@@ -753,13 +786,22 @@
             return null;
         }
 
+        // We're over the minimum guaranteed runtime. Stop the job if we're over config limits,
+        // there are pending jobs that could replace this one, or the device state is not conducive
+        // to long runs.
+
+        if (mPowerManager.isPowerSaveMode()) {
+            return "battery saver";
+        }
+        if (mPowerManager.isDeviceIdleMode()) {
+            return "deep doze";
+        }
+
         // Update config in case memory usage has changed significantly.
         updateCounterConfigLocked();
 
         @WorkType final int workType = context.getRunningJobWorkType();
 
-        // We're over the minimum guaranteed runtime. Stop the job if we're over config limits or
-        // there are pending jobs that could replace this one.
         if (mRunningJobs.size() > mWorkTypeConfig.getMaxTotal()
                 || mWorkCountTracker.isOverTypeLimit(workType)) {
             return "too many jobs running";
@@ -786,13 +828,6 @@
                     return "blocking " + workTypeToString(workType) + " queue";
                 }
             }
-
-            if (mPowerManager.isPowerSaveMode()) {
-                return "battery saver";
-            }
-            if (mPowerManager.isDeviceIdleMode()) {
-                return "deep doze";
-            }
         }
 
         // Easy check. If there are pending jobs of the same work type, then we know that
@@ -975,10 +1010,11 @@
 
     int getJobWorkTypes(@NonNull JobStatus js) {
         int classification = 0;
-        // TODO: create dedicated work type for FGS
         if (shouldRunAsFgUserJob(js)) {
             if (js.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP) {
                 classification |= WORK_TYPE_TOP;
+            } else if (js.lastEvaluatedPriority >= JobInfo.PRIORITY_FOREGROUND_SERVICE) {
+                classification |= WORK_TYPE_FGS;
             } else {
                 classification |= WORK_TYPE_BG;
             }
@@ -999,11 +1035,13 @@
         private static final String KEY_PREFIX_MAX_TOTAL =
                 CONFIG_KEY_PREFIX_CONCURRENCY + "max_total_";
         private static final String KEY_PREFIX_MAX_TOP = CONFIG_KEY_PREFIX_CONCURRENCY + "max_top_";
+        private static final String KEY_PREFIX_MAX_FGS = CONFIG_KEY_PREFIX_CONCURRENCY + "max_fgs_";
         private static final String KEY_PREFIX_MAX_EJ = CONFIG_KEY_PREFIX_CONCURRENCY + "max_ej_";
         private static final String KEY_PREFIX_MAX_BG = CONFIG_KEY_PREFIX_CONCURRENCY + "max_bg_";
         private static final String KEY_PREFIX_MAX_BGUSER =
                 CONFIG_KEY_PREFIX_CONCURRENCY + "max_bguser_";
         private static final String KEY_PREFIX_MIN_TOP = CONFIG_KEY_PREFIX_CONCURRENCY + "min_top_";
+        private static final String KEY_PREFIX_MIN_FGS = CONFIG_KEY_PREFIX_CONCURRENCY + "min_fgs_";
         private static final String KEY_PREFIX_MIN_EJ = CONFIG_KEY_PREFIX_CONCURRENCY + "min_ej_";
         private static final String KEY_PREFIX_MIN_BG = CONFIG_KEY_PREFIX_CONCURRENCY + "min_bg_";
         private static final String KEY_PREFIX_MIN_BGUSER =
@@ -1051,6 +1089,10 @@
                     properties.getInt(KEY_PREFIX_MAX_TOP + mConfigIdentifier,
                             mDefaultMaxAllowedSlots.get(WORK_TYPE_TOP, mMaxTotal))));
             mMaxAllowedSlots.put(WORK_TYPE_TOP, maxTop);
+            final int maxFgs = Math.max(1, Math.min(mMaxTotal,
+                    properties.getInt(KEY_PREFIX_MAX_FGS + mConfigIdentifier,
+                            mDefaultMaxAllowedSlots.get(WORK_TYPE_FGS, mMaxTotal))));
+            mMaxAllowedSlots.put(WORK_TYPE_FGS, maxFgs);
             final int maxEj = Math.max(1, Math.min(mMaxTotal,
                     properties.getInt(KEY_PREFIX_MAX_EJ + mConfigIdentifier,
                             mDefaultMaxAllowedSlots.get(WORK_TYPE_EJ, mMaxTotal))));
@@ -1072,6 +1114,12 @@
                             mDefaultMinReservedSlots.get(WORK_TYPE_TOP))));
             mMinReservedSlots.put(WORK_TYPE_TOP, minTop);
             remaining -= minTop;
+            // Ensure fgs is in the range [0, min(maxFgs, remaining)]
+            final int minFgs = Math.max(0, Math.min(Math.min(maxFgs, remaining),
+                    properties.getInt(KEY_PREFIX_MIN_FGS + mConfigIdentifier,
+                            mDefaultMinReservedSlots.get(WORK_TYPE_FGS))));
+            mMinReservedSlots.put(WORK_TYPE_FGS, minFgs);
+            remaining -= minFgs;
             // Ensure ej is in the range [0, min(maxEj, remaining)]
             final int minEj = Math.max(0, Math.min(Math.min(maxEj, remaining),
                     properties.getInt(KEY_PREFIX_MIN_EJ + mConfigIdentifier,
@@ -1109,6 +1157,10 @@
                     .println();
             pw.print(KEY_PREFIX_MAX_TOP + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_TOP))
                     .println();
+            pw.print(KEY_PREFIX_MIN_FGS + mConfigIdentifier, mMinReservedSlots.get(WORK_TYPE_FGS))
+                    .println();
+            pw.print(KEY_PREFIX_MAX_FGS + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_FGS))
+                    .println();
             pw.print(KEY_PREFIX_MIN_EJ + mConfigIdentifier, mMinReservedSlots.get(WORK_TYPE_EJ))
                     .println();
             pw.print(KEY_PREFIX_MAX_EJ + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_EJ))
@@ -1203,6 +1255,7 @@
         private int mConfigMaxTotal;
         private final SparseIntArray mConfigNumReservedSlots = new SparseIntArray(NUM_WORK_TYPES);
         private final SparseIntArray mConfigAbsoluteMaxSlots = new SparseIntArray(NUM_WORK_TYPES);
+        private final SparseIntArray mRecycledReserved = new SparseIntArray(NUM_WORK_TYPES);
 
         /**
          * Numbers may be lower in this than in {@link #mConfigNumReservedSlots} if there aren't
@@ -1218,11 +1271,14 @@
             mConfigMaxTotal = workTypeConfig.getMaxTotal();
             mConfigNumReservedSlots.put(WORK_TYPE_TOP,
                     workTypeConfig.getMinReserved(WORK_TYPE_TOP));
+            mConfigNumReservedSlots.put(WORK_TYPE_FGS,
+                    workTypeConfig.getMinReserved(WORK_TYPE_FGS));
             mConfigNumReservedSlots.put(WORK_TYPE_EJ, workTypeConfig.getMinReserved(WORK_TYPE_EJ));
             mConfigNumReservedSlots.put(WORK_TYPE_BG, workTypeConfig.getMinReserved(WORK_TYPE_BG));
             mConfigNumReservedSlots.put(WORK_TYPE_BGUSER,
                     workTypeConfig.getMinReserved(WORK_TYPE_BGUSER));
             mConfigAbsoluteMaxSlots.put(WORK_TYPE_TOP, workTypeConfig.getMax(WORK_TYPE_TOP));
+            mConfigAbsoluteMaxSlots.put(WORK_TYPE_FGS, workTypeConfig.getMax(WORK_TYPE_FGS));
             mConfigAbsoluteMaxSlots.put(WORK_TYPE_EJ, workTypeConfig.getMax(WORK_TYPE_EJ));
             mConfigAbsoluteMaxSlots.put(WORK_TYPE_BG, workTypeConfig.getMax(WORK_TYPE_BG));
             mConfigAbsoluteMaxSlots.put(WORK_TYPE_BGUSER, workTypeConfig.getMax(WORK_TYPE_BGUSER));
@@ -1258,15 +1314,10 @@
                 // We don't need to adjust reservations if only one work type was modified
                 // because that work type is the one we're using.
 
-                // 0 is WORK_TYPE_NONE.
-                int workType = 1;
-                int rem = workTypes;
-                while (rem > 0) {
-                    if ((rem & 1) != 0) {
+                for (int workType = 1; workType <= workTypes; workType <<= 1) {
+                    if ((workType & workTypes) == workType) {
                         maybeAdjustReservations(workType);
                     }
-                    rem = rem >>> 1;
-                    workType = workType << 1;
                 }
             }
         }
@@ -1278,21 +1329,11 @@
             int numAdj = 0;
             // We don't know which type we'll classify the job as when we run it yet, so make sure
             // we have space in all applicable slots.
-            if ((workTypes & WORK_TYPE_TOP) == WORK_TYPE_TOP) {
-                mNumPendingJobs.put(WORK_TYPE_TOP, mNumPendingJobs.get(WORK_TYPE_TOP) + adj);
-                numAdj++;
-            }
-            if ((workTypes & WORK_TYPE_EJ) == WORK_TYPE_EJ) {
-                mNumPendingJobs.put(WORK_TYPE_EJ, mNumPendingJobs.get(WORK_TYPE_EJ) + adj);
-                numAdj++;
-            }
-            if ((workTypes & WORK_TYPE_BG) == WORK_TYPE_BG) {
-                mNumPendingJobs.put(WORK_TYPE_BG, mNumPendingJobs.get(WORK_TYPE_BG) + adj);
-                numAdj++;
-            }
-            if ((workTypes & WORK_TYPE_BGUSER) == WORK_TYPE_BGUSER) {
-                mNumPendingJobs.put(WORK_TYPE_BGUSER, mNumPendingJobs.get(WORK_TYPE_BGUSER) + adj);
-                numAdj++;
+            for (int workType = 1; workType <= workTypes; workType <<= 1) {
+                if ((workTypes & workType) == workType) {
+                    mNumPendingJobs.put(workType, mNumPendingJobs.get(workType) + adj);
+                    numAdj++;
+                }
             }
 
             return numAdj;
@@ -1386,105 +1427,45 @@
             mNumUnspecializedRemaining = mConfigMaxTotal;
 
             // Step 1
-            int runTop = mNumRunningJobs.get(WORK_TYPE_TOP);
-            int resTop = runTop;
-            mNumUnspecializedRemaining -= resTop;
-            int runEj = mNumRunningJobs.get(WORK_TYPE_EJ);
-            int resEj = runEj;
-            mNumUnspecializedRemaining -= resEj;
-            int runBg = mNumRunningJobs.get(WORK_TYPE_BG);
-            int resBg = runBg;
-            mNumUnspecializedRemaining -= resBg;
-            int runBgUser = mNumRunningJobs.get(WORK_TYPE_BGUSER);
-            int resBgUser = runBgUser;
-            mNumUnspecializedRemaining -= resBgUser;
+            for (int workType = 1; workType < ALL_WORK_TYPES; workType <<= 1) {
+                int run = mNumRunningJobs.get(workType);
+                mRecycledReserved.put(workType, run);
+                mNumUnspecializedRemaining -= run;
+            }
 
             // Step 2
-            final int numTop = runTop + mNumPendingJobs.get(WORK_TYPE_TOP);
-            int fillUp = Math.max(0, Math.min(mNumUnspecializedRemaining,
-                    Math.min(numTop, mConfigNumReservedSlots.get(WORK_TYPE_TOP) - resTop)));
-            resTop += fillUp;
-            mNumUnspecializedRemaining -= fillUp;
-            final int numEj = runEj + mNumPendingJobs.get(WORK_TYPE_EJ);
-            fillUp = Math.max(0, Math.min(mNumUnspecializedRemaining,
-                    Math.min(numEj, mConfigNumReservedSlots.get(WORK_TYPE_EJ) - resEj)));
-            resEj += fillUp;
-            mNumUnspecializedRemaining -= fillUp;
-            final int numBg = runBg + mNumPendingJobs.get(WORK_TYPE_BG);
-            fillUp = Math.max(0, Math.min(mNumUnspecializedRemaining,
-                    Math.min(numBg, mConfigNumReservedSlots.get(WORK_TYPE_BG) - resBg)));
-            resBg += fillUp;
-            mNumUnspecializedRemaining -= fillUp;
-            final int numBgUser = runBgUser + mNumPendingJobs.get(WORK_TYPE_BGUSER);
-            fillUp = Math.max(0, Math.min(mNumUnspecializedRemaining,
-                    Math.min(numBgUser,
-                            mConfigNumReservedSlots.get(WORK_TYPE_BGUSER) - resBgUser)));
-            resBgUser += fillUp;
-            mNumUnspecializedRemaining -= fillUp;
+            for (int workType = 1; workType < ALL_WORK_TYPES; workType <<= 1) {
+                int num = mNumRunningJobs.get(workType) + mNumPendingJobs.get(workType);
+                int res = mRecycledReserved.get(workType);
+                int fillUp = Math.max(0, Math.min(mNumUnspecializedRemaining,
+                        Math.min(num, mConfigNumReservedSlots.get(workType) - res)));
+                res += fillUp;
+                mRecycledReserved.put(workType, res);
+                mNumUnspecializedRemaining -= fillUp;
+            }
 
             // Step 3
-            int unspecializedAssigned = Math.max(0,
-                    Math.min(mNumUnspecializedRemaining,
-                            Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_TOP), numTop) - resTop));
-            mNumActuallyReservedSlots.put(WORK_TYPE_TOP, resTop + unspecializedAssigned);
-            mNumUnspecializedRemaining -= unspecializedAssigned;
-
-            unspecializedAssigned = Math.max(0,
-                    Math.min(mNumUnspecializedRemaining,
-                            Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_EJ), numEj) - resEj));
-            mNumActuallyReservedSlots.put(WORK_TYPE_EJ, resEj + unspecializedAssigned);
-            mNumUnspecializedRemaining -= unspecializedAssigned;
-
-            unspecializedAssigned = Math.max(0,
-                    Math.min(mNumUnspecializedRemaining,
-                            Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_BG), numBg) - resBg));
-            mNumActuallyReservedSlots.put(WORK_TYPE_BG, resBg + unspecializedAssigned);
-            mNumUnspecializedRemaining -= unspecializedAssigned;
-
-            unspecializedAssigned = Math.max(0,
-                    Math.min(mNumUnspecializedRemaining,
-                            Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_BGUSER), numBgUser)
-                                    - resBgUser));
-            mNumActuallyReservedSlots.put(WORK_TYPE_BGUSER, resBgUser + unspecializedAssigned);
-            mNumUnspecializedRemaining -= unspecializedAssigned;
+            for (int workType = 1; workType < ALL_WORK_TYPES; workType <<= 1) {
+                int num = mNumRunningJobs.get(workType) + mNumPendingJobs.get(workType);
+                int res = mRecycledReserved.get(workType);
+                int unspecializedAssigned = Math.max(0,
+                        Math.min(mNumUnspecializedRemaining,
+                                Math.min(mConfigAbsoluteMaxSlots.get(workType), num) - res));
+                mNumActuallyReservedSlots.put(workType, res + unspecializedAssigned);
+                mNumUnspecializedRemaining -= unspecializedAssigned;
+            }
         }
 
         int canJobStart(int workTypes) {
-            if ((workTypes & WORK_TYPE_TOP) == WORK_TYPE_TOP) {
-                final int maxAllowed = Math.min(
-                        mConfigAbsoluteMaxSlots.get(WORK_TYPE_TOP),
-                        mNumActuallyReservedSlots.get(WORK_TYPE_TOP) + mNumUnspecializedRemaining);
-                if (mNumRunningJobs.get(WORK_TYPE_TOP) + mNumStartingJobs.get(WORK_TYPE_TOP)
-                        < maxAllowed) {
-                    return WORK_TYPE_TOP;
-                }
-            }
-            if ((workTypes & WORK_TYPE_EJ) == WORK_TYPE_EJ) {
-                final int maxAllowed = Math.min(
-                        mConfigAbsoluteMaxSlots.get(WORK_TYPE_EJ),
-                        mNumActuallyReservedSlots.get(WORK_TYPE_EJ) + mNumUnspecializedRemaining);
-                if (mNumRunningJobs.get(WORK_TYPE_EJ) + mNumStartingJobs.get(WORK_TYPE_EJ)
-                        < maxAllowed) {
-                    return WORK_TYPE_EJ;
-                }
-            }
-            if ((workTypes & WORK_TYPE_BG) == WORK_TYPE_BG) {
-                final int maxAllowed = Math.min(
-                        mConfigAbsoluteMaxSlots.get(WORK_TYPE_BG),
-                        mNumActuallyReservedSlots.get(WORK_TYPE_BG) + mNumUnspecializedRemaining);
-                if (mNumRunningJobs.get(WORK_TYPE_BG) + mNumStartingJobs.get(WORK_TYPE_BG)
-                        < maxAllowed) {
-                    return WORK_TYPE_BG;
-                }
-            }
-            if ((workTypes & WORK_TYPE_BGUSER) == WORK_TYPE_BGUSER) {
-                final int maxAllowed = Math.min(
-                        mConfigAbsoluteMaxSlots.get(WORK_TYPE_BGUSER),
-                        mNumActuallyReservedSlots.get(WORK_TYPE_BGUSER)
-                                + mNumUnspecializedRemaining);
-                if (mNumRunningJobs.get(WORK_TYPE_BGUSER) + mNumStartingJobs.get(WORK_TYPE_BGUSER)
-                        < maxAllowed) {
-                    return WORK_TYPE_BGUSER;
+            for (int workType = 1; workType <= workTypes; workType <<= 1) {
+                if ((workTypes & workType) == workType) {
+                    final int maxAllowed = Math.min(
+                            mConfigAbsoluteMaxSlots.get(workType),
+                            mNumActuallyReservedSlots.get(workType) + mNumUnspecializedRemaining);
+                    if (mNumRunningJobs.get(workType) + mNumStartingJobs.get(workType)
+                            < maxAllowed) {
+                        return workType;
+                    }
                 }
             }
             return WORK_TYPE_NONE;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index ac6eb32..8bb03e9 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -151,6 +151,8 @@
     private static final boolean ENFORCE_MAX_JOBS = true;
     /** The maximum number of jobs that we allow an unprivileged app to schedule */
     private static final int MAX_JOBS_PER_APP = 100;
+    /** The number of the most recently completed jobs to keep track of for debugging purposes. */
+    private static final int NUM_COMPLETED_JOB_HISTORY = 20;
 
     @VisibleForTesting
     public static Clock sSystemClock = Clock.systemUTC();
@@ -297,6 +299,10 @@
      */
     boolean mReportedActive;
 
+    private int mLastCompletedJobIndex = 0;
+    private final JobStatus[] mLastCompletedJobs = new JobStatus[NUM_COMPLETED_JOB_HISTORY];
+    private final long[] mLastCompletedJobTimeElapsed = new long[NUM_COMPLETED_JOB_HISTORY];
+
     /**
      * A mapping of which uids are currently in the foreground to their effective priority.
      */
@@ -881,8 +887,10 @@
     }
 
     @Override
-    public void onUserStarting(@NonNull TargetUser user) {
+    public void onUserUnlocked(@NonNull TargetUser user) {
         synchronized (mLock) {
+            // Note that the user has started after its unlocked instead of when the user
+            // actually starts because the storage won't be decrypted until unlock.
             mStartedUsers = ArrayUtils.appendInt(mStartedUsers, user.getUserIdentifier());
         }
         // Let's kick any outstanding jobs for this user.
@@ -890,12 +898,6 @@
     }
 
     @Override
-    public void onUserUnlocking(@NonNull TargetUser user) {
-        // Let's kick any outstanding jobs for this user.
-        mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
-    }
-
-    @Override
     public void onUserStopping(@NonNull TargetUser user) {
         synchronized (mLock) {
             mStartedUsers = ArrayUtils.removeInt(mStartedUsers, user.getUserIdentifier());
@@ -1752,6 +1754,10 @@
             Slog.d(TAG, "Completed " + jobStatus + ", reschedule=" + needsReschedule);
         }
 
+        mLastCompletedJobs[mLastCompletedJobIndex] = jobStatus;
+        mLastCompletedJobTimeElapsed[mLastCompletedJobIndex] = sElapsedRealtimeClock.millis();
+        mLastCompletedJobIndex = (mLastCompletedJobIndex + 1) % NUM_COMPLETED_JOB_HISTORY;
+
         // Intentionally not checking expedited job quota here. An app can't find out if it's run
         // out of quota when it asks JS to reschedule an expedited job. Instead, the rescheduled
         // EJ will just be demoted to a regular job if the app has no EJ quota left.
@@ -2287,7 +2293,8 @@
     /** Returns the maximum amount of time this job could run for. */
     public long getMaxJobExecutionTimeMs(JobStatus job) {
         synchronized (mLock) {
-            return mQuotaController.getMaxJobExecutionTimeMsLocked(job);
+            return Math.min(mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
+                    mQuotaController.getMaxJobExecutionTimeMsLocked(job));
         }
     }
 
@@ -3298,6 +3305,37 @@
                 }
             }
             pw.decreaseIndent();
+
+            pw.println();
+            boolean recentPrinted = false;
+            pw.println("Recently completed jobs:");
+            pw.increaseIndent();
+            for (int r = 1; r <= NUM_COMPLETED_JOB_HISTORY; ++r) {
+                // Print most recent first
+                final int idx = (mLastCompletedJobIndex + NUM_COMPLETED_JOB_HISTORY - r)
+                        % NUM_COMPLETED_JOB_HISTORY;
+                final JobStatus job = mLastCompletedJobs[idx];
+                if (job != null) {
+                    if (!predicate.test(job)) {
+                        continue;
+                    }
+                    recentPrinted = true;
+                    TimeUtils.formatDuration(mLastCompletedJobTimeElapsed[idx], nowElapsed, pw);
+                    pw.println();
+                    // Double indent for readability
+                    pw.increaseIndent();
+                    pw.increaseIndent();
+                    job.dump(pw, true, nowElapsed);
+                    pw.decreaseIndent();
+                    pw.decreaseIndent();
+                }
+            }
+            if (!recentPrinted) {
+                pw.println("None");
+            }
+            pw.decreaseIndent();
+            pw.println();
+
             if (filterUid == -1) {
                 pw.println();
                 pw.print("mReadyToRock="); pw.println(mReadyToRock);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index be91947..2a23d60 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -271,7 +271,9 @@
                 if (job.shouldTreatAsExpeditedJob()) {
                     // TODO(171305774): The job should run on the little cores. We'll probably need
                     // another binding flag for that.
-                    bindFlags = Context.BIND_AUTO_CREATE;
+                    bindFlags = Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
+                            | Context.BIND_ALMOST_PERCEPTIBLE
+                            | Context.BIND_ALLOW_NETWORK_ACCESS;
                 } else {
                     bindFlags = Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
                             | Context.BIND_NOT_PERCEPTIBLE;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index 824fa7f..b70e68b 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -828,8 +828,8 @@
     }
 
     @NonNull
-    private ShrinkableDebits getEJQuotaLocked(final int userId,
-            @NonNull final String packageName) {
+    @VisibleForTesting
+    ShrinkableDebits getEJDebitsLocked(final int userId, @NonNull final String packageName) {
         ShrinkableDebits debits = mEJStats.get(userId, packageName);
         if (debits == null) {
             debits = new ShrinkableDebits(
@@ -931,7 +931,7 @@
 
     @VisibleForTesting
     long getRemainingEJExecutionTimeLocked(final int userId, @NonNull final String packageName) {
-        ShrinkableDebits quota = getEJQuotaLocked(userId, packageName);
+        ShrinkableDebits quota = getEJDebitsLocked(userId, packageName);
         if (quota.getStandbyBucketLocked() == NEVER_INDEX) {
             return 0;
         }
@@ -948,7 +948,7 @@
                 if (ts.endTimeElapsed < windowStartTimeElapsed) {
                     final long duration = ts.endTimeElapsed - ts.startTimeElapsed;
                     remainingMs += duration;
-                    quota.transactOnDebitsLocked(-duration);
+                    quota.transactLocked(-duration);
                     timingSessions.remove(0);
                 } else if (ts.startTimeElapsed < windowStartTimeElapsed) {
                     remainingMs += windowStartTimeElapsed - ts.startTimeElapsed;
@@ -960,15 +960,16 @@
             }
         }
 
+        TopAppTimer topAppTimer = mTopAppTrackers.get(userId, packageName);
+        if (topAppTimer != null && topAppTimer.isActive()) {
+            remainingMs += topAppTimer.getPendingReward(nowElapsed);
+        }
+
         Timer timer = mEJPkgTimers.get(userId, packageName);
         if (timer == null) {
             return remainingMs;
         }
-        // There's a case where the debits tally is 0 but a currently running HPJ still counts
-        // towards quota. If the app gets a reward in this case, the reward is lost and the HPJ
-        // run is still fully counted.
-        // TODO(171305774)/STOPSHIP: make sure getting rewards while HPJ currently executing isn't
-        // treated negatively
+
         return remainingMs - timer.getCurrentDuration(sElapsedRealtimeClock.millis());
     }
 
@@ -994,12 +995,18 @@
         if (standbyBucket == NEVER_INDEX) {
             return 0;
         }
+
         List<TimingSession> sessions = mTimingSessions.get(userId, packageName);
+        final ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket);
         if (sessions == null || sessions.size() == 0) {
+            // Regular ACTIVE case. Since the bucket size equals the allowed time, the app jobs can
+            // essentially run until they reach the maximum limit.
+            if (stats.windowSizeMs == mAllowedTimePerPeriodMs) {
+                return mMaxExecutionTimeMs;
+            }
             return mAllowedTimePerPeriodMs;
         }
 
-        final ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket);
         final long startWindowElapsed = nowElapsed - stats.windowSizeMs;
         final long startMaxElapsed = nowElapsed - MAX_PERIOD_MS;
         final long allowedTimeRemainingMs = mAllowedTimePerPeriodMs - stats.executionTimeInWindowMs;
@@ -1081,7 +1088,7 @@
         }
 
         final long nowElapsed = sElapsedRealtimeClock.millis();
-        ShrinkableDebits quota = getEJQuotaLocked(userId, packageName);
+        ShrinkableDebits quota = getEJDebitsLocked(userId, packageName);
         final long limitMs = getEJLimitMsLocked(packageName, quota.getStandbyBucketLocked());
         final long startWindowElapsed = Math.max(0, nowElapsed - mEJLimitWindowSizeMs);
         long remainingDeadSpaceMs = remainingExecutionTimeMs;
@@ -1372,6 +1379,11 @@
     @VisibleForTesting
     void saveTimingSession(final int userId, @NonNull final String packageName,
             @NonNull final TimingSession session, boolean isExpedited) {
+        saveTimingSession(userId, packageName, session, isExpedited, 0);
+    }
+
+    private void saveTimingSession(final int userId, @NonNull final String packageName,
+            @NonNull final TimingSession session, boolean isExpedited, long debitAdjustment) {
         synchronized (mLock) {
             final SparseArrayMap<String, List<TimingSession>> sessionMap =
                     isExpedited ? mEJTimingSessions : mTimingSessions;
@@ -1382,8 +1394,9 @@
             }
             sessions.add(session);
             if (isExpedited) {
-                final ShrinkableDebits quota = getEJQuotaLocked(userId, packageName);
-                quota.transactOnDebitsLocked(session.endTimeElapsed - session.startTimeElapsed);
+                final ShrinkableDebits quota = getEJDebitsLocked(userId, packageName);
+                quota.transactLocked(session.endTimeElapsed - session.startTimeElapsed
+                        + debitAdjustment);
             } else {
                 // Adding a new session means that the current stats are now incorrect.
                 invalidateAllExecutionStatsLocked(userId, packageName);
@@ -1396,15 +1409,34 @@
     private void grantRewardForInstantEvent(
             final int userId, @NonNull final String packageName, final long credit) {
         synchronized (mLock) {
-            final ShrinkableDebits quota = getEJQuotaLocked(userId, packageName);
-            quota.transactOnDebitsLocked(-credit);
-            if (maybeUpdateConstraintForPkgLocked(sElapsedRealtimeClock.millis(),
-                    userId, packageName)) {
+            final long nowElapsed = sElapsedRealtimeClock.millis();
+            final ShrinkableDebits quota = getEJDebitsLocked(userId, packageName);
+            if (transactQuotaLocked(userId, packageName, nowElapsed, quota, credit)
+                    && maybeUpdateConstraintForPkgLocked(nowElapsed, userId, packageName)) {
                 mStateChangedListener.onControllerStateChanged();
             }
         }
     }
 
+    private boolean transactQuotaLocked(final int userId, @NonNull final String packageName,
+            final long nowElapsed, @NonNull ShrinkableDebits debits, final long credit) {
+        final long oldTally = debits.getTallyLocked();
+        final long leftover = debits.transactLocked(-credit);
+        if (DEBUG) {
+            Slog.d(TAG, "debits overflowed by " + leftover);
+        }
+        boolean changed = oldTally != debits.getTallyLocked();
+        if (leftover != 0) {
+            // Only adjust timer if its active.
+            final Timer ejTimer = mEJPkgTimers.get(userId, packageName);
+            if (ejTimer != null && ejTimer.isActive()) {
+                ejTimer.updateDebitAdjustment(nowElapsed, leftover);
+                changed = true;
+            }
+        }
+        return changed;
+    }
+
     private final class EarliestEndTimeFunctor implements Consumer<List<TimingSession>> {
         public long earliestEndElapsed = Long.MAX_VALUE;
 
@@ -1875,7 +1907,8 @@
         }
     }
 
-    private static final class ShrinkableDebits {
+    @VisibleForTesting
+    static final class ShrinkableDebits {
         /** The amount of quota remaining. Can be negative if limit changes. */
         private long mDebitTally;
         private int mStandbyBucket;
@@ -1893,8 +1926,11 @@
          * Negative if the tally should decrease (therefore increasing available quota);
          * or positive if the tally should increase (therefore decreasing available quota).
          */
-        void transactOnDebitsLocked(final long amount) {
+        long transactLocked(final long amount) {
+            final long leftover = amount < 0 && Math.abs(amount) > mDebitTally
+                    ? mDebitTally + amount : 0;
             mDebitTally = Math.max(0, mDebitTally + amount);
+            return leftover;
         }
 
         void setStandbyBucketLocked(int standbyBucket) {
@@ -1927,6 +1963,7 @@
         private final ArraySet<JobStatus> mRunningBgJobs = new ArraySet<>();
         private long mStartTimeElapsed;
         private int mBgJobCount;
+        private long mDebitAdjustment;
 
         Timer(int uid, int userId, String packageName, boolean regularJobTimer) {
             mPkg = new Package(userId, packageName);
@@ -1957,6 +1994,7 @@
                 if (mRunningBgJobs.size() == 1) {
                     // Started tracking the first job.
                     mStartTimeElapsed = sElapsedRealtimeClock.millis();
+                    mDebitAdjustment = 0;
                     if (mRegularJobTimer) {
                         // Starting the timer means that all cached execution stats are now
                         // incorrect.
@@ -1988,6 +2026,11 @@
             }
         }
 
+        void updateDebitAdjustment(long nowElapsed, long debit) {
+            // Make sure we don't have a credit larger than the expected session.
+            mDebitAdjustment = Math.max(mDebitAdjustment + debit, mStartTimeElapsed - nowElapsed);
+        }
+
         /**
          * Stops tracking all jobs and cancels any pending alarms. This should only be called if
          * the Timer is not going to be used anymore.
@@ -2003,7 +2046,8 @@
                 return;
             }
             TimingSession ts = new TimingSession(mStartTimeElapsed, nowElapsed, mBgJobCount);
-            saveTimingSession(mPkg.userId, mPkg.packageName, ts, !mRegularJobTimer);
+            saveTimingSession(mPkg.userId, mPkg.packageName, ts, !mRegularJobTimer,
+                    mDebitAdjustment);
             mBgJobCount = 0;
             // Don't reset the tracked jobs list as we need to keep tracking the current number
             // of jobs.
@@ -2030,7 +2074,7 @@
 
         long getCurrentDuration(long nowElapsed) {
             synchronized (mLock) {
-                return !isActive() ? 0 : nowElapsed - mStartTimeElapsed;
+                return !isActive() ? 0 : nowElapsed - mStartTimeElapsed + mDebitAdjustment;
             }
         }
 
@@ -2059,6 +2103,7 @@
                 // Start timing from unplug.
                 if (mRunningBgJobs.size() > 0) {
                     mStartTimeElapsed = nowElapsed;
+                    mDebitAdjustment = 0;
                     // NOTE: this does have the unfortunate consequence that if the device is
                     // repeatedly plugged in and unplugged, or an app changes foreground state
                     // very frequently, the job count for a package may be artificially high.
@@ -2128,6 +2173,11 @@
             pw.print(", ");
             pw.print(mBgJobCount);
             pw.print(" running bg jobs");
+            if (!mRegularJobTimer) {
+                pw.print(" (debit adj=");
+                pw.print(mDebitAdjustment);
+                pw.print(")");
+            }
             pw.println();
             pw.increaseIndent();
             for (int i = 0; i < mRunningBgJobs.size(); i++) {
@@ -2171,6 +2221,21 @@
             mPkg = new Package(userId, packageName);
         }
 
+        private int calculateTimeChunks(final long nowElapsed) {
+            final long totalTopTimeMs = nowElapsed - mStartTimeElapsed;
+            int numTimeChunks = (int) (totalTopTimeMs / mEJTopAppTimeChunkSizeMs);
+            final long remainderMs = totalTopTimeMs % mEJTopAppTimeChunkSizeMs;
+            if (remainderMs >= SECOND_IN_MILLIS) {
+                // "Round up"
+                numTimeChunks++;
+            }
+            return numTimeChunks;
+        }
+
+        long getPendingReward(final long nowElapsed) {
+            return mEJRewardTopAppMs * calculateTimeChunks(nowElapsed);
+        }
+
         void processEventLocked(@NonNull UsageEvents.Event event) {
             final long nowElapsed = sElapsedRealtimeClock.millis();
             switch (event.getEventType()) {
@@ -2186,21 +2251,16 @@
                     final UsageEvents.Event existingEvent =
                             mActivities.removeReturnOld(event.mInstanceId);
                     if (existingEvent != null && mActivities.size() == 0) {
-                        final long totalTopTimeMs = nowElapsed - mStartTimeElapsed;
-                        int numTimeChunks = (int) (totalTopTimeMs / mEJTopAppTimeChunkSizeMs);
-                        final long remainderMs = totalTopTimeMs % mEJTopAppTimeChunkSizeMs;
-                        if (remainderMs >= SECOND_IN_MILLIS) {
-                            // "Round up"
-                            numTimeChunks++;
-                        }
+                        final long pendingReward = getPendingReward(nowElapsed);
                         if (DEBUG) {
-                            Slog.d(TAG,
-                                    "Crediting " + mPkg + " for " + numTimeChunks + " time chunks");
+                            Slog.d(TAG, "Crediting " + mPkg + " " + pendingReward + "ms"
+                                    + " for " + calculateTimeChunks(nowElapsed) + " time chunks");
                         }
-                        final ShrinkableDebits quota =
-                                getEJQuotaLocked(mPkg.userId, mPkg.packageName);
-                        quota.transactOnDebitsLocked(-mEJRewardTopAppMs * numTimeChunks);
-                        if (maybeUpdateConstraintForPkgLocked(nowElapsed,
+                        final ShrinkableDebits debits =
+                                getEJDebitsLocked(mPkg.userId, mPkg.packageName);
+                        if (transactQuotaLocked(mPkg.userId, mPkg.packageName,
+                                nowElapsed, debits, pendingReward)
+                                && maybeUpdateConstraintForPkgLocked(nowElapsed,
                                 mPkg.userId, mPkg.packageName)) {
                             mStateChangedListener.onControllerStateChanged();
                         }
@@ -2321,7 +2381,7 @@
          */
         @Override
         public void onUsageEvent(int userId, @NonNull UsageEvents.Event event) {
-            mHandler.obtainMessage(MSG_PROCESS_USAGE_EVENT, userId, 0, event);
+            mHandler.obtainMessage(MSG_PROCESS_USAGE_EVENT, userId, 0, event).sendToTarget();
         }
     }
 
@@ -2408,7 +2468,6 @@
     }
 
     private class QcHandler extends Handler {
-        private boolean mIsProcessing;
 
         QcHandler(Looper looper) {
             super(looper);
@@ -2417,8 +2476,6 @@
         @Override
         public void handleMessage(Message msg) {
             synchronized (mLock) {
-                mIsProcessing = true;
-
                 switch (msg.what) {
                     case MSG_REACHED_QUOTA: {
                         Package pkg = (Package) msg.obj;
@@ -2539,6 +2596,10 @@
                         final int userId = msg.arg1;
                         final UsageEvents.Event event = (UsageEvents.Event) msg.obj;
                         final String pkgName = event.getPackageName();
+                        if (DEBUG) {
+                            Slog.d(TAG, "Processing event " + event.getEventType()
+                                    + " for " + string(userId, pkgName));
+                        }
                         switch (event.getEventType()) {
                             case UsageEvents.Event.ACTIVITY_RESUMED:
                             case UsageEvents.Event.ACTIVITY_PAUSED:
@@ -2604,8 +2665,6 @@
                     }
                 }
             }
-
-            mIsProcessing = false;
         }
     }
 
@@ -3883,11 +3942,6 @@
         return mQcConstants;
     }
 
-    @VisibleForTesting
-    boolean isActiveBackgroundProcessing() {
-        return mHandler.mIsProcessing;
-    }
-
     //////////////////////////// DATA DUMP //////////////////////////////
 
     @Override
diff --git a/apex/jobscheduler/service/jni/Android.bp b/apex/jobscheduler/service/jni/Android.bp
index 4bcc165..c630217 100644
--- a/apex/jobscheduler/service/jni/Android.bp
+++ b/apex/jobscheduler/service/jni/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
 cc_library_shared {
     name: "libalarm_jni",
 
diff --git a/apex/media/aidl/private/android/media/IMediaCommunicationService.aidl b/apex/media/aidl/private/android/media/IMediaCommunicationService.aidl
index 3d50d14..fb3172b 100644
--- a/apex/media/aidl/private/android/media/IMediaCommunicationService.aidl
+++ b/apex/media/aidl/private/android/media/IMediaCommunicationService.aidl
@@ -15,7 +15,17 @@
  */
 package android.media;
 
+import android.media.Session2Token;
+import android.media.IMediaCommunicationServiceCallback;
+import android.media.MediaParceledListSlice;
+
 /** {@hide} */
 interface IMediaCommunicationService {
+    void notifySession2Created(in Session2Token sessionToken);
+    boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid);
+    MediaParceledListSlice getSession2Tokens(int userId);
+
+    void registerCallback(IMediaCommunicationServiceCallback callback, String packageName);
+    void unregisterCallback(IMediaCommunicationServiceCallback callback);
 }
 
diff --git a/apex/media/aidl/private/android/media/IMediaCommunicationServiceCallback.aidl b/apex/media/aidl/private/android/media/IMediaCommunicationServiceCallback.aidl
new file mode 100644
index 0000000..3d5321c
--- /dev/null
+++ b/apex/media/aidl/private/android/media/IMediaCommunicationServiceCallback.aidl
@@ -0,0 +1,26 @@
+/**
+ * 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.media;
+
+import android.media.Session2Token;
+import android.media.MediaParceledListSlice;
+
+/** {@hide} */
+interface IMediaCommunicationServiceCallback {
+    void onSession2Created(in Session2Token token);
+    void onSession2Changed(in MediaParceledListSlice tokens);
+}
+
diff --git a/apex/media/framework/api/current.txt b/apex/media/framework/api/current.txt
index a2366df..1beef40 100644
--- a/apex/media/framework/api/current.txt
+++ b/apex/media/framework/api/current.txt
@@ -26,6 +26,7 @@
   }
 
   public class MediaCommunicationManager {
+    method @NonNull public java.util.List<android.media.Session2Token> getSession2Tokens();
     method @IntRange(from=1) public int getVersion();
   }
 
diff --git a/apex/media/framework/api/module-lib-current.txt b/apex/media/framework/api/module-lib-current.txt
index ad9114f..eb6397a1 100644
--- a/apex/media/framework/api/module-lib-current.txt
+++ b/apex/media/framework/api/module-lib-current.txt
@@ -1,6 +1,16 @@
 // Signature format: 2.0
 package android.media {
 
+  public class MediaCommunicationManager {
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void registerSessionCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaCommunicationManager.SessionCallback);
+    method public void unregisterSessionCallback(@NonNull android.media.MediaCommunicationManager.SessionCallback);
+  }
+
+  public static interface MediaCommunicationManager.SessionCallback {
+    method public default void onSession2TokenCreated(@NonNull android.media.Session2Token);
+    method public default void onSession2TokensChanged(@NonNull java.util.List<android.media.Session2Token>);
+  }
+
   public class MediaFrameworkInitializer {
     method public static void registerServiceWrappers();
     method public static void setMediaServiceManager(@NonNull android.media.MediaServiceManager);
diff --git a/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java b/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
index 685cf0d..906071f 100644
--- a/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
+++ b/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
@@ -39,10 +39,12 @@
  for handling newer video codec format and media features.
 
  <p>
- Android 12 introduces seamless media transcoding feature. By default, Android assumes apps can
- support playback of all media formats. Apps that would like to request that media be transcoded
- into a more compatible format should declare their media capabilities in a media_capabilities
- .xml resource file and add it as a property tag in the AndroidManifest.xml file. Here is a example:
+ Android 12 introduces Compatible media transcoding feature.  See
+ <a href="https://developer.android.com/about/versions/12/features#compatible_media_transcoding">
+ Compatible media transcoding</a>. By default, Android assumes apps can support playback of all
+ media formats. Apps that would like to request that media be transcoded into a more compatible
+ format should declare their media capabilities in a media_capabilities.xml resource file and add it
+ as a property tag in the AndroidManifest.xml file. Here is a example:
  <pre>
  {@code
  <media-capabilities xmlns:android="http://schemas.android.com/apk/res/android">
diff --git a/apex/media/framework/java/android/media/Controller2Link.java b/apex/media/framework/java/android/media/Controller2Link.java
index 04185e7..8eefec7 100644
--- a/apex/media/framework/java/android/media/Controller2Link.java
+++ b/apex/media/framework/java/android/media/Controller2Link.java
@@ -26,7 +26,7 @@
 import java.util.Objects;
 
 /**
- * Handles incoming commands from {@link MediaSession2} to both {@link MediaController2}.
+ * Handles incoming commands from {@link MediaSession2} to {@link MediaController2}.
  * @hide
  */
 // @SystemApi
diff --git a/apex/media/framework/java/android/media/MediaCommunicationManager.java b/apex/media/framework/java/android/media/MediaCommunicationManager.java
index e686076..9ec25fe 100644
--- a/apex/media/framework/java/android/media/MediaCommunicationManager.java
+++ b/apex/media/framework/java/android/media/MediaCommunicationManager.java
@@ -15,18 +15,36 @@
  */
 package android.media;
 
+import static android.Manifest.permission.MEDIA_CONTENT_CONTROL;
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
+import android.annotation.CallbackExecutor;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
+import android.media.session.MediaSession;
+import android.media.session.MediaSessionManager;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.media.MediaBrowserService;
+import android.util.Log;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.modules.utils.build.SdkLevel;
 
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Executor;
+
 /**
  * Provides support for interacting with {@link android.media.MediaSession2 MediaSession2s}
  * that applications have published to express their ongoing media playback state.
  */
-// TODO: Add notifySession2Created() and sendMessage().
 @SystemService(Context.MEDIA_COMMUNICATION_SERVICE)
 public class MediaCommunicationManager {
     private static final String TAG = "MediaCommunicationManager";
@@ -44,6 +62,13 @@
     private final Context mContext;
     private final IMediaCommunicationService mService;
 
+    private final Object mLock = new Object();
+    private final CopyOnWriteArrayList<SessionCallbackRecord> mTokenCallbackRecords =
+            new CopyOnWriteArrayList<>();
+
+    @GuardedBy("mLock")
+    private MediaCommunicationServiceCallbackStub mCallbackStub;
+
     /**
      * @hide
      */
@@ -64,4 +89,197 @@
     public @IntRange(from = 1) int getVersion() {
         return CURRENT_VERSION;
     }
+
+    /**
+     * Notifies that a new {@link MediaSession2} with type {@link Session2Token#TYPE_SESSION} is
+     * created.
+     * @param token newly created session2 token
+     * @hide
+     */
+    public void notifySession2Created(@NonNull Session2Token token) {
+        Objects.requireNonNull(token, "token shouldn't be null");
+        if (token.getType() != Session2Token.TYPE_SESSION) {
+            throw new IllegalArgumentException("token's type should be TYPE_SESSION");
+        }
+        try {
+            mService.notifySession2Created(token);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Checks whether the remote user is a trusted app.
+     * <p>
+     * An app is trusted if the app holds the
+     * {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission or has an enabled
+     * notification listener.
+     *
+     * @param userInfo The remote user info from either
+     *            {@link MediaSession#getCurrentControllerInfo()} or
+     *            {@link MediaBrowserService#getCurrentBrowserInfo()}.
+     * @return {@code true} if the remote user is trusted or {@code false} otherwise.
+     * @hide
+     */
+    public boolean isTrustedForMediaControl(@NonNull MediaSessionManager.RemoteUserInfo userInfo) {
+        Objects.requireNonNull(userInfo, "userInfo shouldn't be null");
+        if (userInfo.getPackageName() == null) {
+            return false;
+        }
+        try {
+            return mService.isTrusted(
+                    userInfo.getPackageName(), userInfo.getPid(), userInfo.getUid());
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot communicate with the service.", e);
+        }
+        return false;
+    }
+
+    /**
+     * This API is not generally intended for third party application developers.
+     * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+     * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
+     * Library</a> for consistent behavior across all devices.
+     * <p>
+     * Gets a list of {@link Session2Token} with type {@link Session2Token#TYPE_SESSION} for the
+     * current user.
+     * <p>
+     * Although this API can be used without any restriction, each session owners can accept or
+     * reject your uses of {@link MediaSession2}.
+     *
+     * @return A list of {@link Session2Token}.
+     */
+    @NonNull
+    public List<Session2Token> getSession2Tokens() {
+        return getSession2Tokens(UserHandle.myUserId());
+    }
+
+    /**
+     * Adds a callback to be notified when the list of active sessions changes.
+     * <p>
+     * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be
+     * held by the calling app.
+     * </p>
+     * @hide
+     */
+    @SystemApi(client = MODULE_LIBRARIES)
+    @RequiresPermission(MEDIA_CONTENT_CONTROL)
+    public void registerSessionCallback(@CallbackExecutor @NonNull Executor executor,
+            @NonNull SessionCallback callback) {
+        Objects.requireNonNull(executor, "executor must not be null");
+        Objects.requireNonNull(callback, "callback must not be null");
+
+        if (!mTokenCallbackRecords.addIfAbsent(
+                new SessionCallbackRecord(executor, callback))) {
+            Log.w(TAG, "registerSession2TokenCallback: Ignoring the same callback");
+            return;
+        }
+        synchronized (mLock) {
+            if (mCallbackStub == null) {
+                MediaCommunicationServiceCallbackStub callbackStub =
+                        new MediaCommunicationServiceCallbackStub();
+                try {
+                    mService.registerCallback(callbackStub, mContext.getPackageName());
+                    mCallbackStub = callbackStub;
+                } catch (RemoteException ex) {
+                    Log.e(TAG, "Failed to register callback.", ex);
+                }
+            }
+        }
+    }
+
+    /**
+     * Stops receiving active sessions updates on the specified callback.
+     * @hide
+     */
+    @SystemApi(client = MODULE_LIBRARIES)
+    public void unregisterSessionCallback(@NonNull SessionCallback callback) {
+        if (!mTokenCallbackRecords.remove(
+                new SessionCallbackRecord(null, callback))) {
+            Log.w(TAG, "unregisterSession2TokenCallback: Ignoring an unknown callback.");
+            return;
+        }
+        synchronized (mLock) {
+            if (mCallbackStub != null && mTokenCallbackRecords.isEmpty()) {
+                try {
+                    mService.unregisterCallback(mCallbackStub);
+                } catch (RemoteException ex) {
+                    Log.e(TAG, "Failed to unregister callback.", ex);
+                }
+                mCallbackStub = null;
+            }
+        }
+    }
+
+    private List<Session2Token> getSession2Tokens(int userId) {
+        try {
+            MediaParceledListSlice slice = mService.getSession2Tokens(userId);
+            return slice == null ? Collections.emptyList() : slice.getList();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to get session tokens", e);
+        }
+        return Collections.emptyList();
+    }
+
+    /**
+     * Callback for listening to changes to the sessions.
+     * @see #registerSessionCallback(Executor, SessionCallback)
+     * @hide
+     */
+    @SystemApi(client = MODULE_LIBRARIES)
+    public interface SessionCallback {
+        /**
+         * Called when a new {@link MediaSession2 media session2} is created.
+         * @param token the newly created token
+         */
+        default void onSession2TokenCreated(@NonNull Session2Token token) {}
+
+        /**
+         * Called when {@link #getSession2Tokens() session tokens} are changed.
+         */
+        default void onSession2TokensChanged(@NonNull List<Session2Token> tokens) {}
+    }
+
+    private static final class SessionCallbackRecord {
+        public final Executor executor;
+        public final SessionCallback callback;
+
+        SessionCallbackRecord(Executor executor, SessionCallback callback) {
+            this.executor = executor;
+            this.callback = callback;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(callback);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof SessionCallbackRecord)) {
+                return false;
+            }
+            return Objects.equals(this.callback, ((SessionCallbackRecord) obj).callback);
+        }
+    }
+
+    class MediaCommunicationServiceCallbackStub extends IMediaCommunicationServiceCallback.Stub {
+        @Override
+        public void onSession2Created(Session2Token token) throws RemoteException {
+            for (SessionCallbackRecord record : mTokenCallbackRecords) {
+                record.executor.execute(() -> record.callback.onSession2TokenCreated(token));
+            }
+        }
+
+        @Override
+        public void onSession2Changed(MediaParceledListSlice tokens) throws RemoteException {
+            List<Session2Token> tokenList = tokens.getList();
+            for (SessionCallbackRecord record : mTokenCallbackRecords) {
+                record.executor.execute(() -> record.callback.onSession2TokensChanged(tokenList));
+            }
+        }
+    }
 }
diff --git a/apex/media/framework/java/android/media/MediaSession2.java b/apex/media/framework/java/android/media/MediaSession2.java
index 6560afe..6397ba3 100644
--- a/apex/media/framework/java/android/media/MediaSession2.java
+++ b/apex/media/framework/java/android/media/MediaSession2.java
@@ -32,7 +32,6 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
-import android.media.session.MediaSessionManager;
 import android.media.session.MediaSessionManager.RemoteUserInfo;
 import android.os.BadParcelableException;
 import android.os.Bundle;
@@ -87,7 +86,7 @@
     private final String mSessionId;
     private final PendingIntent mSessionActivity;
     private final Session2Token mSessionToken;
-    private final MediaSessionManager mSessionManager;
+    private final MediaCommunicationManager mCommunicationManager;
     private final Handler mResultHandler;
 
     //@GuardedBy("mLock")
@@ -115,8 +114,7 @@
         mSessionStub = new Session2Link(this);
         mSessionToken = new Session2Token(Process.myUid(), TYPE_SESSION, context.getPackageName(),
                 mSessionStub, tokenExtras);
-        mSessionManager = (MediaSessionManager) mContext.getSystemService(
-                Context.MEDIA_SESSION_SERVICE);
+        mCommunicationManager = mContext.getSystemService(MediaCommunicationManager.class);
         // NOTE: mResultHandler uses main looper, so this MUST NOT be blocked.
         mResultHandler = new Handler(context.getMainLooper());
         mClosed = false;
@@ -352,7 +350,7 @@
 
         final ControllerInfo controllerInfo = new ControllerInfo(
                 remoteUserInfo,
-                mSessionManager.isTrustedForMediaControl(remoteUserInfo),
+                mCommunicationManager.isTrustedForMediaControl(remoteUserInfo),
                 controller,
                 connectionHints);
         mCallbackExecutor.execute(() -> {
@@ -608,8 +606,8 @@
             // Notify framework about the newly create session after the constructor is finished.
             // Otherwise, framework may access the session before the initialization is finished.
             try {
-                MediaSessionManager manager = (MediaSessionManager) mContext.getSystemService(
-                        Context.MEDIA_SESSION_SERVICE);
+                MediaCommunicationManager manager =
+                        mContext.getSystemService(MediaCommunicationManager.class);
                 manager.notifySession2Created(session2.getToken());
             } catch (Exception e) {
                 session2.close();
diff --git a/apex/media/service/Android.bp b/apex/media/service/Android.bp
index 5b24cfa..9b3399e 100644
--- a/apex/media/service/Android.bp
+++ b/apex/media/service/Android.bp
@@ -11,6 +11,15 @@
 // 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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 filegroup {
     name: "service-media-s-sources",
     srcs: [
@@ -38,4 +47,3 @@
         "com.android.media",
     ],
 }
-
diff --git a/apex/media/service/java/com/android/server/media/MediaCommunicationService.java b/apex/media/service/java/com/android/server/media/MediaCommunicationService.java
index 0468fdf..06de3f8 100644
--- a/apex/media/service/java/com/android/server/media/MediaCommunicationService.java
+++ b/apex/media/service/java/com/android/server/media/MediaCommunicationService.java
@@ -15,27 +15,538 @@
  */
 package com.android.server.media;
 
-import android.content.Context;
-import android.media.IMediaCommunicationService;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.os.UserHandle.ALL;
+import static android.os.UserHandle.getUserHandleForUid;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.media.IMediaCommunicationService;
+import android.media.IMediaCommunicationServiceCallback;
+import android.media.MediaController2;
+import android.media.MediaParceledListSlice;
+import android.media.Session2CommandGroup;
+import android.media.Session2Token;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+
+import com.android.internal.annotations.GuardedBy;
 import com.android.server.SystemService;
 
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.stream.Collectors;
+
 /**
- * A system service that managers {@link android.media.MediaSession2} creations
+ * A system service that manages {@link android.media.MediaSession2} creations
  * and their ongoing media playback state.
  * @hide
  */
 public class MediaCommunicationService extends SystemService {
+    private static final String TAG = "MediaCommunicationService";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    final Context mContext;
+
+    private final Object mLock = new Object();
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
+
+    @GuardedBy("mLock")
+    private final SparseIntArray mFullUserIds = new SparseIntArray();
+    @GuardedBy("mLock")
+    private final SparseArray<FullUserRecord> mUserRecords = new SparseArray<>();
+
+    private final Executor mRecordExecutor = Executors.newSingleThreadExecutor();
+    @GuardedBy("mLock")
+    private final List<CallbackRecord> mCallbackRecords = new ArrayList<>();
+    final NotificationManager mNotificationManager;
 
     public MediaCommunicationService(Context context) {
         super(context);
+        mContext = context;
+        mNotificationManager = context.getSystemService(NotificationManager.class);
     }
 
     @Override
     public void onStart() {
         publishBinderService(Context.MEDIA_COMMUNICATION_SERVICE, new Stub());
+        updateUser();
+    }
+
+    @Override
+    public void onUserStarting(@NonNull TargetUser user) {
+        if (DEBUG) Log.d(TAG, "onUserStarting: " + user);
+        updateUser();
+    }
+
+    @Override
+    public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+        if (DEBUG) Log.d(TAG, "onUserSwitching: " + to);
+        updateUser();
+    }
+
+    @Override
+    public void onUserStopped(@NonNull TargetUser targetUser) {
+        int userId = targetUser.getUserHandle().getIdentifier();
+
+        if (DEBUG) Log.d(TAG, "onUserStopped: " + userId);
+        synchronized (mLock) {
+            FullUserRecord user = getFullUserRecordLocked(userId);
+            if (user != null) {
+                if (user.getFullUserId() == userId) {
+                    user.destroySessionsForUserLocked(UserHandle.ALL.getIdentifier());
+                    mUserRecords.remove(userId);
+                } else {
+                    user.destroySessionsForUserLocked(userId);
+                }
+            }
+            updateUser();
+        }
+    }
+
+    @Nullable
+    CallbackRecord findCallbackRecordLocked(@Nullable IMediaCommunicationServiceCallback callback) {
+        if (callback == null) {
+            return null;
+        }
+        for (CallbackRecord record : mCallbackRecords) {
+            if (Objects.equals(callback.asBinder(), record.mCallback.asBinder())) {
+                return record;
+            }
+        }
+        return null;
+    }
+
+    private FullUserRecord getFullUserRecordLocked(int userId) {
+        int fullUserId = mFullUserIds.get(userId, -1);
+        if (fullUserId < 0) {
+            return null;
+        }
+        return mUserRecords.get(fullUserId);
+    }
+
+    private boolean hasMediaControlPermission(int pid, int uid) {
+        // Check if it's system server or has MEDIA_CONTENT_CONTROL.
+        // Note that system server doesn't have MEDIA_CONTENT_CONTROL, so we need extra
+        // check here.
+        if (uid == Process.SYSTEM_UID || mContext.checkPermission(
+                android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
+                == PackageManager.PERMISSION_GRANTED) {
+            return true;
+        } else if (DEBUG) {
+            Log.d(TAG, "uid(" + uid + ") hasn't granted MEDIA_CONTENT_CONTROL");
+        }
+        return false;
+    }
+
+    private void updateUser() {
+        UserManager manager = mContext.getSystemService(UserManager.class);
+        List<UserHandle> allUsers = manager.getUserHandles(/*excludeDying=*/false);
+
+        synchronized (mLock) {
+            mFullUserIds.clear();
+            if (allUsers != null) {
+                for (UserHandle user : allUsers) {
+                    UserHandle parent = manager.getProfileParent(user);
+                    if (parent != null) {
+                        mFullUserIds.put(user.getIdentifier(), parent.getIdentifier());
+                    } else {
+                        mFullUserIds.put(user.getIdentifier(), user.getIdentifier());
+                        if (mUserRecords.get(user.getIdentifier()) == null) {
+                            mUserRecords.put(user.getIdentifier(),
+                                    new FullUserRecord(user.getIdentifier()));
+                        }
+                    }
+                }
+            }
+            // Ensure that the current full user exists.
+            int currentFullUserId = ActivityManager.getCurrentUser();
+            FullUserRecord currentFullUserRecord = mUserRecords.get(currentFullUserId);
+            if (currentFullUserRecord == null) {
+                Log.w(TAG, "Cannot find FullUserInfo for the current user " + currentFullUserId);
+                currentFullUserRecord = new FullUserRecord(currentFullUserId);
+                mUserRecords.put(currentFullUserId, currentFullUserRecord);
+            }
+            mFullUserIds.put(currentFullUserId, currentFullUserId);
+        }
+    }
+
+    void dispatchSessionCreated(Session2Token token) {
+        for (CallbackRecord record : mCallbackRecords) {
+            if (record.mUserId != ALL.getIdentifier()
+                    && record.mUserId != getUserHandleForUid(token.getUid()).getIdentifier()) {
+                continue;
+            }
+            try {
+                record.mCallback.onSession2Created(token);
+            } catch (RemoteException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    void onSessionDied(Session2Record record) {
+        synchronized (mLock) {
+            destroySessionLocked(record);
+        }
+    }
+
+    private void destroySessionLocked(Session2Record session) {
+        if (DEBUG) {
+            Log.d(TAG, "Destroying " + session);
+        }
+        if (session.isClosed()) {
+            Log.w(TAG, "Destroying already destroyed session. Ignoring.");
+            return;
+        }
+
+        FullUserRecord user = getFullUserRecordLocked(session.getUserId());
+
+        if (user != null) {
+            user.removeSession(session);
+        }
+
+        session.close();
     }
 
     private class Stub extends IMediaCommunicationService.Stub {
+        @Override
+        public void notifySession2Created(Session2Token sessionToken) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+
+            try {
+                if (DEBUG) {
+                    Log.d(TAG, "Session2 is created " + sessionToken);
+                }
+                if (uid != sessionToken.getUid()) {
+                    throw new SecurityException("Unexpected Session2Token's UID, expected=" + uid
+                            + " but actually=" + sessionToken.getUid());
+                }
+                synchronized (mLock) {
+                    int userId = getUserHandleForUid(sessionToken.getUid()).getIdentifier();
+                    FullUserRecord user = getFullUserRecordLocked(userId);
+                    if (user == null) {
+                        Log.w(TAG, "notifySession2Created: Ignore session of an unknown user");
+                        return;
+                    }
+                    user.addSession(new Session2Record(MediaCommunicationService.this,
+                            sessionToken, mRecordExecutor));
+                    mHandler.post(() -> dispatchSessionCreated(sessionToken));
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        /**
+         * Returns if the controller's package is trusted (i.e. has either MEDIA_CONTENT_CONTROL
+         * permission or an enabled notification listener)
+         *
+         * @param controllerPackageName package name of the controller app
+         * @param controllerPid pid of the controller app
+         * @param controllerUid uid of the controller app
+         */
+        @Override
+        public boolean isTrusted(String controllerPackageName, int controllerPid,
+                int controllerUid) {
+            final int uid = Binder.getCallingUid();
+            final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                // Don't perform check between controllerPackageName and controllerUid.
+                // When an (activity|service) runs on the another apps process by specifying
+                // android:process in the AndroidManifest.xml, then PID and UID would have the
+                // running process' information instead of the (activity|service) that has created
+                // MediaController.
+                // Note that we can use Context#getOpPackageName() instead of
+                // Context#getPackageName() for getting package name that matches with the PID/UID,
+                // but it doesn't tell which package has created the MediaController, so useless.
+                return hasMediaControlPermission(controllerPid, controllerUid)
+                        || hasEnabledNotificationListener(
+                        userId, controllerPackageName, controllerUid);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public MediaParceledListSlice getSession2Tokens(int userId) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+
+            try {
+                // Check that they can make calls on behalf of the user and get the final user id
+                int resolvedUserId = handleIncomingUser(pid, uid, userId, null);
+                List<Session2Token> result;
+                synchronized (mLock) {
+                    FullUserRecord user = getFullUserRecordLocked(userId);
+                    result = user.getSession2Tokens(resolvedUserId);
+                }
+                return new MediaParceledListSlice(result);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void registerCallback(IMediaCommunicationServiceCallback callback,
+                String packageName) throws RemoteException {
+            Objects.requireNonNull(callback, "callback should not be null");
+            Objects.requireNonNull(packageName, "packageName should not be null");
+
+            synchronized (mLock) {
+                if (findCallbackRecordLocked(callback) == null) {
+
+                    CallbackRecord record = new CallbackRecord(callback, packageName,
+                            Binder.getCallingUid(), Binder.getCallingPid());
+                    mCallbackRecords.add(record);
+                    try {
+                        callback.asBinder().linkToDeath(record, 0);
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "Failed to register callback", e);
+                        mCallbackRecords.remove(record);
+                    }
+                } else {
+                    Log.e(TAG, "registerCallback is called with already registered callback. "
+                            + "packageName=" + packageName);
+                }
+            }
+        }
+
+        @Override
+        public void unregisterCallback(IMediaCommunicationServiceCallback callback)
+                throws RemoteException {
+            synchronized (mLock) {
+                CallbackRecord existingRecord = findCallbackRecordLocked(callback);
+                if (existingRecord != null) {
+                    mCallbackRecords.remove(existingRecord);
+                    callback.asBinder().unlinkToDeath(existingRecord, 0);
+                } else {
+                    Log.e(TAG, "unregisterCallback is called with unregistered callback.");
+                }
+            }
+        }
+
+        private boolean hasEnabledNotificationListener(int callingUserId,
+                String controllerPackageName, int controllerUid) {
+            int controllerUserId = UserHandle.getUserHandleForUid(controllerUid).getIdentifier();
+            if (callingUserId != controllerUserId) {
+                // Enabled notification listener only works within the same user.
+                return false;
+            }
+
+            if (mNotificationManager.hasEnabledNotificationListener(controllerPackageName,
+                    UserHandle.getUserHandleForUid(controllerUid))) {
+                return true;
+            }
+            if (DEBUG) {
+                Log.d(TAG, controllerPackageName + " (uid=" + controllerUid
+                        + ") doesn't have an enabled notification listener");
+            }
+            return false;
+        }
+
+        // Handles incoming user by checking whether the caller has permission to access the
+        // given user id's information or not. Permission is not necessary if the given user id is
+        // equal to the caller's user id, but if not, the caller needs to have the
+        // INTERACT_ACROSS_USERS_FULL permission. Otherwise, a security exception will be thrown.
+        // The return value will be the given user id, unless the given user id is
+        // UserHandle.CURRENT, which will return the ActivityManager.getCurrentUser() value instead.
+        private int handleIncomingUser(int pid, int uid, int userId, String packageName) {
+            int callingUserId = UserHandle.getUserHandleForUid(uid).getIdentifier();
+            if (userId == callingUserId) {
+                return userId;
+            }
+
+            boolean canInteractAcrossUsersFull = mContext.checkPermission(
+                    INTERACT_ACROSS_USERS_FULL, pid, uid) == PackageManager.PERMISSION_GRANTED;
+            if (canInteractAcrossUsersFull) {
+                if (userId == UserHandle.CURRENT.getIdentifier()) {
+                    return ActivityManager.getCurrentUser();
+                }
+                return userId;
+            }
+
+            throw new SecurityException("Permission denied while calling from " + packageName
+                    + " with user id: " + userId + "; Need to run as either the calling user id ("
+                    + callingUserId + "), or with " + INTERACT_ACROSS_USERS_FULL + " permission");
+        }
+    }
+
+    final class CallbackRecord implements IBinder.DeathRecipient {
+        private final IMediaCommunicationServiceCallback mCallback;
+        private final String mPackageName;
+        private final int mUid;
+        private int mPid;
+        private final int mUserId;
+
+        CallbackRecord(IMediaCommunicationServiceCallback callback,
+                String packageName, int uid, int pid) {
+            mCallback = callback;
+            mPackageName = packageName;
+            mUid = uid;
+            mPid = pid;
+            mUserId = (mContext.checkPermission(
+                    INTERACT_ACROSS_USERS_FULL, pid, uid) == PackageManager.PERMISSION_GRANTED)
+                    ? ALL.getIdentifier() : UserHandle.getUserHandleForUid(mUid).getIdentifier();
+        }
+
+        @Override
+        public String toString() {
+            return "CallbackRecord[callback=" + mCallback + ", pkg=" + mPackageName
+                    + ", uid=" + mUid + ", pid=" + mPid + "]";
+        }
+
+        @Override
+        public void binderDied() {
+            synchronized (mLock) {
+                mCallbackRecords.remove(this);
+            }
+        }
+    }
+
+    final class FullUserRecord {
+        private final int mFullUserId;
+        /** Sorted list of media sessions */
+        private final List<Session2Record> mSessionRecords = new ArrayList<>();
+
+        FullUserRecord(int fullUserId) {
+            mFullUserId = fullUserId;
+        }
+
+        public void addSession(Session2Record record) {
+            mSessionRecords.add(record);
+        }
+
+        public void removeSession(Session2Record record) {
+            mSessionRecords.remove(record);
+            //TODO: Handle if the removed session was the media button session.
+        }
+
+        public int getFullUserId() {
+            return mFullUserId;
+        }
+
+        public List<Session2Token> getSession2Tokens(int userId) {
+            return mSessionRecords.stream()
+                    .filter(record -> record.isActive()
+                            && (userId == UserHandle.ALL.getIdentifier()
+                                    || record.getUserId() == userId))
+                    .map(Session2Record::getSessionToken)
+                    .collect(Collectors.toList());
+        }
+
+        public void destroySessionsForUserLocked(int userId) {
+            synchronized (mLock) {
+                for (Session2Record record : mSessionRecords) {
+                    if (userId == UserHandle.ALL.getIdentifier()
+                            || record.getUserId() == userId) {
+                        destroySessionLocked(record);
+                    }
+                }
+            }
+        }
+    }
+
+    static final class Session2Record {
+        private final Session2Token mSessionToken;
+        private final Object mLock = new Object();
+        private final WeakReference<MediaCommunicationService> mServiceRef;
+        @GuardedBy("mLock")
+        private final MediaController2 mController;
+
+        @GuardedBy("mLock")
+        private boolean mIsConnected;
+        @GuardedBy("mLock")
+        private boolean mIsClosed;
+
+        Session2Record(MediaCommunicationService service, Session2Token token,
+                Executor controllerExecutor) {
+            mServiceRef = new WeakReference<>(service);
+            mSessionToken = token;
+            mController = new MediaController2.Builder(service.getContext(), token)
+                    .setControllerCallback(controllerExecutor, new Controller2Callback())
+                    .build();
+        }
+
+        public int getUserId() {
+            return UserHandle.getUserHandleForUid(mSessionToken.getUid()).getIdentifier();
+        }
+
+        public boolean isActive() {
+            synchronized (mLock) {
+                return mIsConnected;
+            }
+        }
+
+        public boolean isClosed() {
+            synchronized (mLock) {
+                return mIsClosed;
+            }
+        }
+
+        public void close() {
+            synchronized (mLock) {
+                mIsClosed = true;
+                // Call close regardless of the mIsConnected. This may be called when it's not yet
+                // connected.
+                mController.close();
+            }
+        }
+
+        public Session2Token getSessionToken() {
+            return mSessionToken;
+        }
+
+        private class Controller2Callback extends MediaController2.ControllerCallback {
+            @Override
+            public void onConnected(MediaController2 controller,
+                    Session2CommandGroup allowedCommands) {
+                if (DEBUG) {
+                    Log.d(TAG, "connected to " + mSessionToken + ", allowed=" + allowedCommands);
+                }
+                synchronized (mLock) {
+                    mIsConnected = true;
+                }
+                MediaCommunicationService service = mServiceRef.get();
+                if (service != null) {
+                    //TODO: notify session state changed
+                }
+            }
+
+            @Override
+            public void onDisconnected(MediaController2 controller) {
+                if (DEBUG) {
+                    Log.d(TAG, "disconnected from " + mSessionToken);
+                }
+                synchronized (mLock) {
+                    mIsConnected = false;
+                }
+                MediaCommunicationService service = mServiceRef.get();
+                if (service != null) {
+                    service.onSessionDied(Session2Record.this);
+                }
+            }
+        }
     }
 }
diff --git a/api/Android.bp b/api/Android.bp
index 15c1dfc..1d4698e 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -40,6 +40,7 @@
         ":art.module.public.api{.public.api.txt}",
         ":conscrypt.module.public.api{.public.api.txt}",
         ":framework-appsearch{.public.api.txt}",
+        ":framework-connectivity{.public.api.txt}",
         ":framework-graphics{.public.api.txt}",
         ":framework-media{.public.api.txt}",
         ":framework-mediaprovider{.public.api.txt}",
@@ -95,6 +96,7 @@
         ":art.module.public.api{.public.stubs.source}",
         ":conscrypt.module.public.api{.public.stubs.source}",
         ":framework-appsearch{.public.stubs.source}",
+        ":framework-connectivity{.public.stubs.source}",
         ":framework-graphics{.public.stubs.source}",
         ":framework-media{.public.stubs.source}",
         ":framework-mediaprovider{.public.stubs.source}",
@@ -120,6 +122,7 @@
         ":art.module.public.api{.public.removed-api.txt}",
         ":conscrypt.module.public.api{.public.removed-api.txt}",
         ":framework-appsearch{.public.removed-api.txt}",
+        ":framework-connectivity{.public.removed-api.txt}",
         ":framework-graphics{.public.removed-api.txt}",
         ":framework-media{.public.removed-api.txt}",
         ":framework-mediaprovider{.public.removed-api.txt}",
@@ -155,6 +158,7 @@
     srcs: [
         ":android.net.ipsec.ike{.system.api.txt}",
         ":framework-appsearch{.system.api.txt}",
+        ":framework-connectivity{.system.api.txt}",
         ":framework-graphics{.system.api.txt}",
         ":framework-media{.system.api.txt}",
         ":framework-mediaprovider{.system.api.txt}",
@@ -208,6 +212,7 @@
     srcs: [
         ":android.net.ipsec.ike{.system.removed-api.txt}",
         ":framework-appsearch{.system.removed-api.txt}",
+        ":framework-connectivity{.system.removed-api.txt}",
         ":framework-graphics{.system.removed-api.txt}",
         ":framework-media{.system.removed-api.txt}",
         ":framework-mediaprovider{.system.removed-api.txt}",
@@ -243,6 +248,7 @@
     srcs: [
         ":android.net.ipsec.ike{.module-lib.api.txt}",
         ":framework-appsearch{.module-lib.api.txt}",
+        ":framework-connectivity{.module-lib.api.txt}",
         ":framework-graphics{.module-lib.api.txt}",
         ":framework-media{.module-lib.api.txt}",
         ":framework-mediaprovider{.module-lib.api.txt}",
@@ -298,6 +304,7 @@
     srcs: [
         ":android.net.ipsec.ike{.module-lib.removed-api.txt}",
         ":framework-appsearch{.module-lib.removed-api.txt}",
+        ":framework-connectivity{.module-lib.removed-api.txt}",
         ":framework-graphics{.module-lib.removed-api.txt}",
         ":framework-media{.module-lib.removed-api.txt}",
         ":framework-mediaprovider{.module-lib.removed-api.txt}",
diff --git a/cmds/abx/Android.bp b/cmds/abx/Android.bp
index 333aced..50a0b75 100644
--- a/cmds/abx/Android.bp
+++ b/cmds/abx/Android.bp
@@ -1,4 +1,21 @@
 
+package {
+    default_applicable_licenses: ["frameworks_base_cmds_abx_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_cmds_abx_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 java_binary {
     name: "abx",
     wrapper: "abx",
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 4b7eda0..ed717c4 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -19,7 +19,6 @@
 import android.annotation.IntDef;
 import android.annotation.UserIdInt;
 import android.app.backup.BackupManager;
-import android.app.backup.BackupManager.OperationType;
 import android.app.backup.BackupManagerMonitor;
 import android.app.backup.BackupProgress;
 import android.app.backup.BackupTransport;
@@ -667,7 +666,7 @@
 
         // The rest of the 'list' options work with a restore session on the current transport
         try {
-            mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null, OperationType.BACKUP);
+            mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null);
             if (mRestore == null) {
                 System.err.println(BMGR_ERR_NO_RESTORESESSION_FOR_USER + userId);
                 return;
@@ -822,7 +821,7 @@
 
         try {
             boolean didRestore = false;
-            mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null, OperationType.BACKUP);
+            mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null);
             if (mRestore == null) {
                 System.err.println(BMGR_ERR_NO_RESTORESESSION_FOR_USER + userId);
                 return;
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.cpp b/cmds/hid/jni/com_android_commands_hid_Device.cpp
index 422c2be..2cda57d 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.cpp
+++ b/cmds/hid/jni/com_android_commands_hid_Device.cpp
@@ -48,6 +48,7 @@
 static struct {
     jmethodID onDeviceOpen;
     jmethodID onDeviceGetReport;
+    jmethodID onDeviceSetReport;
     jmethodID onDeviceOutput;
     jmethodID onDeviceError;
 } gDeviceCallbackClassInfo;
@@ -113,10 +114,18 @@
     checkAndClearException(env, "onDeviceGetReport");
 }
 
-void DeviceCallback::onDeviceOutput(uint8_t eventId, uint8_t rType,
+void DeviceCallback::onDeviceSetReport(uint8_t rType,
                                     const std::vector<uint8_t>& data) {
     JNIEnv* env = getJNIEnv();
-    env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceOutput, eventId, rType,
+    env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceSetReport, rType,
+                        toJbyteArray(env, data).get());
+    checkAndClearException(env, "onDeviceSetReport");
+}
+
+void DeviceCallback::onDeviceOutput(uint8_t rType,
+                                    const std::vector<uint8_t>& data) {
+    JNIEnv* env = getJNIEnv();
+    env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceOutput, rType,
                         toJbyteArray(env, data).get());
     checkAndClearException(env, "onDeviceOutput");
 }
@@ -262,7 +271,7 @@
                 ALOGD("Received SET_REPORT: id=%" PRIu32 " rnum=%" PRIu8 " data=%s", set_report.id,
                       set_report.rnum, toString(data).c_str());
             }
-            mDeviceCallback->onDeviceOutput(UHID_SET_REPORT, set_report.rtype, data);
+            mDeviceCallback->onDeviceSetReport(set_report.rtype, data);
             break;
         }
         case UHID_OUTPUT: {
@@ -271,7 +280,7 @@
             if (DEBUG_OUTPUT) {
                 ALOGD("UHID_OUTPUT rtype=%" PRIu8 " data=%s", output.rtype, toString(data).c_str());
             }
-            mDeviceCallback->onDeviceOutput(UHID_OUTPUT, output.rtype, data);
+            mDeviceCallback->onDeviceOutput(output.rtype, data);
             break;
         }
         default: {
@@ -366,8 +375,10 @@
             env->GetMethodID(clazz, "onDeviceOpen", "()V");
     uhid::gDeviceCallbackClassInfo.onDeviceGetReport =
             env->GetMethodID(clazz, "onDeviceGetReport", "(II)V");
+    uhid::gDeviceCallbackClassInfo.onDeviceSetReport =
+            env->GetMethodID(clazz, "onDeviceSetReport", "(B[B)V");
     uhid::gDeviceCallbackClassInfo.onDeviceOutput =
-            env->GetMethodID(clazz, "onDeviceOutput", "(BB[B)V");
+            env->GetMethodID(clazz, "onDeviceOutput", "(B[B)V");
     uhid::gDeviceCallbackClassInfo.onDeviceError =
             env->GetMethodID(clazz, "onDeviceError", "()V");
     if (uhid::gDeviceCallbackClassInfo.onDeviceOpen == NULL ||
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.h b/cmds/hid/jni/com_android_commands_hid_Device.h
index bb73132..d10a9aa 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.h
+++ b/cmds/hid/jni/com_android_commands_hid_Device.h
@@ -31,7 +31,8 @@
 
     void onDeviceOpen();
     void onDeviceGetReport(uint32_t requestId, uint8_t reportId);
-    void onDeviceOutput(uint8_t eventId, uint8_t rType, const std::vector<uint8_t>& data);
+    void onDeviceSetReport(uint8_t rType, const std::vector<uint8_t>& data);
+    void onDeviceOutput(uint8_t rType, const std::vector<uint8_t>& data);
     void onDeviceError();
 
 private:
diff --git a/cmds/hid/src/com/android/commands/hid/Device.java b/cmds/hid/src/com/android/commands/hid/Device.java
index 37d0b1c..95b1e9a 100644
--- a/cmds/hid/src/com/android/commands/hid/Device.java
+++ b/cmds/hid/src/com/android/commands/hid/Device.java
@@ -199,8 +199,8 @@
             mHandler.sendMessageAtTime(msg, mTimeToSend);
         }
 
-        // native callback
-        public void onDeviceOutput(byte eventId, byte rtype, byte[] data) {
+        // Send out the report to HID command output
+        private void sendReportOutput(byte eventId, byte rtype, byte[] data) {
             JSONObject json = new JSONObject();
             try {
                 json.put("eventId", eventId);
@@ -221,6 +221,18 @@
                 throw new RuntimeException(e);
             }
 
+        }
+
+        // native callback
+        public void onDeviceSetReport(byte rtype, byte[] data) {
+            // We don't need to reply for the SET_REPORT but just send it to HID output for test
+            // verification.
+            sendReportOutput(UHID_EVENT_TYPE_SET_REPORT, rtype, data);
+        }
+
+        // native callback
+        public void onDeviceOutput(byte rtype, byte[] data) {
+            sendReportOutput(UHID_EVENT_TYPE_UHID_OUTPUT, rtype, data);
             if (mOutputs == null) {
                 Log.e(TAG, "Received OUTPUT request, but 'outputs' section is not found");
                 return;
diff --git a/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java b/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java
index a0361d0..ca9df39 100644
--- a/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java
+++ b/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java
@@ -182,6 +182,8 @@
                 mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
             } else if (opt.equals("--rc") || opt.equals("--require-charging")) {
                 mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_REQUIRE_CHARGING, true);
+            } else if (opt.equals("--ej") || opt.equals("--schedule-as-ej")) {
+                mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, true);
             } else if (opt.equals("-e") || opt.equals("--es") || opt.equals("--extra-string")) {
                 final String key = nextArgRequired();
                 final String value = nextArgRequired();
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index f85e30d..9c044b5 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -66,6 +66,7 @@
     private static final String COMMAND_SET_PHONE_ACCOUNT_SUGGESTION_COMPONENT =
             "set-phone-acct-suggestion-component";
     private static final String COMMAND_UNREGISTER_PHONE_ACCOUNT = "unregister-phone-account";
+    private static final String COMMAND_SET_CALL_DIAGNOSTIC_SERVICE = "set-call-diagnostic-service";
     private static final String COMMAND_SET_DEFAULT_DIALER = "set-default-dialer";
     private static final String COMMAND_GET_DEFAULT_DIALER = "get-default-dialer";
     private static final String COMMAND_STOP_BLOCK_SUPPRESSION = "stop-block-suppression";
@@ -112,6 +113,7 @@
                 + "usage: telecom register-sim-phone-account <COMPONENT> <ID> <USER_SN>"
                 + " <LABEL> <ADDRESS>\n"
                 + "usage: telecom unregister-phone-account <COMPONENT> <ID> <USER_SN>\n"
+                + "usage: telecom set-call-diagnostic-service <PACKAGE>\n"
                 + "usage: telecom set-default-dialer <PACKAGE>\n"
                 + "usage: telecom get-default-dialer\n"
                 + "usage: telecom get-system-dialer\n"
@@ -131,6 +133,7 @@
                 + "telecom set-phone-account-disabled: Disables the given phone account, if it"
                         + " has already been registered with telecom.\n"
                 + "\n"
+                + "telecom set-call-diagnostic-service: overrides call diagnostic service.\n"
                 + "telecom set-default-dialer: Sets the override default dialer to the given"
                         + " component; this will override whatever the dialer role is set to.\n"
                 + "\n"
@@ -206,6 +209,9 @@
             case COMMAND_SET_PHONE_ACCOUNT_SUGGESTION_COMPONENT:
                 runSetTestPhoneAcctSuggestionComponent();
                 break;
+            case COMMAND_SET_CALL_DIAGNOSTIC_SERVICE:
+                runSetCallDiagnosticService();
+                break;
             case COMMAND_REGISTER_SIM_PHONE_ACCOUNT:
                 runRegisterSimPhoneAccount();
                 break;
@@ -323,6 +329,13 @@
         mTelecomService.addOrRemoveTestCallCompanionApp(packageName, isAddedBool);
     }
 
+    private void runSetCallDiagnosticService() throws RemoteException {
+        String packageName = nextArg();
+        if ("default".equals(packageName)) packageName = null;
+        mTelecomService.setTestCallDiagnosticService(packageName);
+        System.out.println("Success - " + packageName + " set as call diagnostic service.");
+    }
+
     private void runSetTestPhoneAcctSuggestionComponent() throws RemoteException {
         final String componentName = nextArg();
         mTelecomService.setTestPhoneAcctSuggestionComponent(componentName);
diff --git a/cmds/uinput/Android.bp b/cmds/uinput/Android.bp
index 0d7fed2..260cfc7 100644
--- a/cmds/uinput/Android.bp
+++ b/cmds/uinput/Android.bp
@@ -1,6 +1,23 @@
 // Copyright 2020 The Android Open Source Project
 //
 
+package {
+    default_applicable_licenses: ["frameworks_base_cmds_uinput_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_cmds_uinput_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 java_binary {
     name: "uinput",
     wrapper: "uinput",
@@ -15,4 +32,4 @@
     srcs: [
         "src/com/android/commands/uinput/InputAbsInfo.aidl",
     ],
-}
\ No newline at end of file
+}
diff --git a/cmds/uinput/jni/Android.bp b/cmds/uinput/jni/Android.bp
index 199bbbd..c56adc3 100644
--- a/cmds/uinput/jni/Android.bp
+++ b/cmds/uinput/jni/Android.bp
@@ -1,3 +1,12 @@
+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_cmds_uinput_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_cmds_uinput_license"],
+}
+
 cc_library_shared {
     name: "libuinputcommand_jni",
 
diff --git a/config/dirty-image-objects b/config/dirty-image-objects
index 2dfe019..dfd091c 100644
--- a/config/dirty-image-objects
+++ b/config/dirty-image-objects
@@ -28,359 +28,359 @@
 # Then, grep for lines containing "Private dirty object" from the output.
 # This particular file was generated by dumping systemserver and systemui.
 #
-android.accounts.Account
-android.accounts.OnAccountsUpdateListener
-android.animation.LayoutTransition
-android.app.ActivityManager
-android.app.ActivityManager$OnUidImportanceListener
-android.app.ActivityTaskManager
-android.app.ActivityThread
-android.app.admin.DevicePolicyManager
-android.app.AlarmManager
-android.app.Application
-android.app.AppOpsManager
-android.app.backup.BackupManager
-android.app.ContextImpl
-android.app.INotificationManager
-android.app.Notification$BigPictureStyle
-android.app.Notification$BigTextStyle
-android.app.Notification$InboxStyle
-android.app.NotificationChannel
-android.app.NotificationChannelGroup
-android.app.NotificationManager
-android.app.PendingIntent
-android.app.PendingIntent$OnFinished
-android.app.QueuedWork
-android.app.ResourcesManager
-android.app.WallpaperManager
-android.app.WindowConfiguration
-android.bluetooth.BluetoothAdapter
-android.bluetooth.BluetoothDevice
-android.bluetooth.BluetoothProfile
-android.bluetooth.IBluetoothA2dp
-android.bluetooth.IBluetoothHeadsetPhone
-android.bluetooth.IBluetoothHidDevice
-android.bluetooth.IBluetoothHidHost
-android.bluetooth.IBluetoothMap
-android.bluetooth.IBluetoothPan
-android.bluetooth.IBluetoothPbap
-android.bluetooth.IBluetoothSap
-android.content.ClipboardManager$OnPrimaryClipChangedListener
-android.content.ComponentName
-android.content.ContentProvider$PipeDataWriter
-android.content.ContentResolver
-android.content.Context
-android.content.Intent
-android.content.pm.PackageManager$OnPermissionsChangedListener
-android.content.pm.VersionedPackage
-android.content.res.Configuration
-android.content.SharedPreferences$OnSharedPreferenceChangeListener
-android.database.CursorWindow
-android.database.sqlite.SQLiteCompatibilityWalFlags
-android.database.sqlite.SQLiteDatabase$CursorFactory
-android.database.sqlite.SQLiteGlobal
-android.database.sqlite.SQLiteTransactionListener
-android.ddm.DdmHandleAppName
-android.graphics.Bitmap
-android.graphics.Canvas
-android.graphics.drawable.AdaptiveIconDrawable
-android.graphics.drawable.ColorDrawable
-android.graphics.drawable.GradientDrawable
-android.graphics.drawable.Icon
-android.graphics.drawable.InsetDrawable
-android.graphics.drawable.RippleDrawable
-android.graphics.drawable.VectorDrawable$VGroup
-android.graphics.ImageDecoder
-android.graphics.Rect
-android.graphics.TemporaryBuffer
-android.hardware.biometrics.BiometricSourceType
-android.hardware.display.ColorDisplayManager$ColorDisplayManagerInternal
-android.hardware.display.DisplayManagerGlobal
-android.hardware.display.NightDisplayListener$Callback
-android.hardware.input.InputManager
-android.hardware.input.InputManager$InputDeviceListener
-android.hardware.SensorPrivacyManager
-android.hardware.SystemSensorManager
-android.icu.impl.OlsonTimeZone
-android.icu.text.BreakIterator
-android.icu.text.Collator
-android.icu.text.DateFormat$BooleanAttribute
-android.icu.text.DateTimePatternGenerator$DTPGflags
-android.icu.text.PluralRules$Operand
-android.icu.util.TimeZone
-android.location.GpsStatus$Listener
-android.location.LocationListener
-android.media.AudioManager
-android.media.MediaRouter
-android.media.PlayerBase
-android.media.session.MediaSessionManager
-android.net.apf.ApfCapabilities
-android.net.ConnectivityManager
-android.net.ConnectivityManager$OnNetworkActiveListener
-android.net.ConnectivityThread$Singleton
-android.net.IpConfiguration$IpAssignment
-android.net.IpConfiguration$ProxySettings
-android.net.IpPrefix
-android.net.LinkAddress
-android.net.LinkProperties
-android.net.Network
-android.net.NetworkCapabilities
-android.net.NetworkInfo
-android.net.NetworkInfo$State
-android.net.NetworkRequest
-android.net.NetworkRequest$Type
-android.net.RouteInfo
-android.net.StringNetworkSpecifier
-android.net.TrafficStats
-android.net.UidRange
-android.net.Uri$HierarchicalUri
-android.net.Uri$StringUri
-android.net.wifi.WifiManager
-android.net.wifi.WifiManager$SoftApCallback
-android.os.AsyncResult
-android.os.AsyncTask
-android.os.BinderProxy
-android.os.Bundle
-android.os.DeadObjectException
-android.os.Environment
-android.os.FileObserver
-android.os.Handler
-android.os.IDeviceIdleController
-android.os.LocaleList
-android.os.Looper
-android.os.Message
-android.os.ParcelUuid
-android.os.Process
-android.os.RecoverySystem
-android.os.ServiceManager
-android.os.storage.StorageManager
-android.os.StrictMode
-android.os.Trace
-android.os.WorkSource
-android.os.WorkSource$WorkChain
-android.permission.PermissionManager
-android.provider.FontsContract
-android.provider.Settings$SettingNotFoundException
-android.renderscript.RenderScriptCacheDir
-android.security.IKeyChainService
-android.security.keystore.AndroidKeyStoreProvider
-android.security.net.config.ApplicationConfig
-android.security.net.config.SystemCertificateSource$NoPreloadHolder
-android.telecom.PhoneAccountHandle
-android.telephony.AnomalyReporter
-android.telephony.CellSignalStrengthCdma
-android.telephony.CellSignalStrengthGsm
-android.telephony.CellSignalStrengthLte
-android.telephony.CellSignalStrengthNr
-android.telephony.CellSignalStrengthTdscdma
-android.telephony.CellSignalStrengthWcdma
-android.telephony.DataSpecificRegistrationInfo
-android.telephony.emergency.EmergencyNumber
-android.telephony.ims.ImsMmTelManager$CapabilityCallback$CapabilityBinder
-android.telephony.ims.ImsMmTelManager$RegistrationCallback$RegistrationBinder
-android.telephony.ims.ImsReasonInfo
-android.telephony.ims.ProvisioningManager$Callback$CallbackBinder
-android.telephony.ModemActivityInfo
-android.telephony.ModemInfo
-android.telephony.NetworkRegistrationInfo
-android.telephony.NetworkService
-android.telephony.TelephonyManager
-android.telephony.VoiceSpecificRegistrationInfo
-android.text.format.DateFormat
-android.text.method.SingleLineTransformationMethod
-android.text.Selection$MemoryTextWatcher
-android.text.SpanWatcher
-android.text.style.AlignmentSpan
-android.text.style.CharacterStyle
-android.text.style.LeadingMarginSpan
-android.text.style.LineBackgroundSpan
-android.text.style.LineHeightSpan
-android.text.style.MetricAffectingSpan
-android.text.style.ReplacementSpan
-android.text.style.SuggestionSpan
-android.text.style.TabStopSpan
-android.text.TextUtils
-android.text.TextWatcher
-android.transition.ChangeClipBounds
-android.transition.ChangeImageTransform
-android.transition.ChangeTransform
-android.util.ArrayMap
-android.util.ArraySet
-android.util.DisplayMetrics
-android.util.EventLog
-android.util.Log
-android.util.Patterns
-android.view.AbsSavedState$1
-android.view.accessibility.AccessibilityManager
-android.view.accessibility.AccessibilityManager$AccessibilityServicesStateChangeListener
-android.view.accessibility.AccessibilityManager$TouchExplorationStateChangeListener
-android.view.accessibility.AccessibilityNodeIdManager
-android.view.autofill.AutofillManager
-android.view.autofill.Helper
-android.view.Choreographer
-android.view.inputmethod.InputMethodManager
-android.view.IWindowManager
-android.view.PointerIcon
-android.view.RemoteAnimationAdapter
-android.view.ThreadedRenderer
-android.view.View
-android.view.View$OnHoverListener
-android.view.ViewRootImpl
-android.view.ViewStub
-android.view.ViewStub$OnInflateListener
-android.view.ViewTreeObserver
-android.view.WindowManager$LayoutParams
-android.view.WindowManagerGlobal
-android.widget.ActionMenuPresenter$OverflowMenuButton
-android.widget.ActionMenuView
-android.widget.Button
-android.widget.CheckBox
-android.widget.FrameLayout
-android.widget.ImageButton
-android.widget.ImageView
-android.widget.LinearLayout
-android.widget.RelativeLayout
-android.widget.SeekBar
-android.widget.Space
-android.widget.TextView
-android.widget.Toolbar
-byte[]
-com.android.ims.ImsManager
-com.android.internal.logging.MetricsLogger
-com.android.internal.os.BackgroundThread
-com.android.internal.os.BinderInternal
-com.android.internal.os.BinderInternal$BinderProxyLimitListener
-com.android.internal.os.RuntimeInit
-com.android.internal.os.SomeArgs
-com.android.internal.policy.DecorView
-com.android.internal.statusbar.IStatusBarService
-com.android.internal.telephony.AppSmsManager
-android.telephony.CallerInfoAsyncQuery$OnQueryCompleteListener
-com.android.internal.telephony.CarrierActionAgent
-com.android.internal.telephony.cat.CatService
-com.android.internal.telephony.cat.IconLoader
-com.android.internal.telephony.cat.RilMessageDecoder
-com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager
-com.android.internal.telephony.cdma.EriManager
-com.android.internal.telephony.CellularNetworkValidator
-com.android.internal.telephony.CommandException
-com.android.internal.telephony.dataconnection.DataConnection$DcActivatingState
-com.android.internal.telephony.dataconnection.DataConnection$DcActiveState
-com.android.internal.telephony.dataconnection.DataConnection$DcInactiveState
-com.android.internal.telephony.dataconnection.DataEnabledSettings
-com.android.internal.telephony.dataconnection.DcTracker
-com.android.internal.telephony.euicc.EuiccCardController
-com.android.internal.telephony.euicc.EuiccController
-com.android.internal.telephony.GsmAlphabet
-com.android.internal.telephony.GsmCdmaCallTracker
-com.android.internal.telephony.GsmCdmaPhone
-com.android.internal.telephony.IccPhoneBookInterfaceManager
-com.android.internal.telephony.IccSmsInterfaceManager
-com.android.internal.telephony.ims.ImsResolver
-com.android.internal.telephony.imsphone.ImsExternalCallTracker
-com.android.internal.telephony.imsphone.ImsPhone
-com.android.internal.telephony.imsphone.ImsPhoneCallTracker
-com.android.internal.telephony.ims.RcsMessageStoreController
-com.android.internal.telephony.IntentBroadcaster
-com.android.internal.telephony.ITelephonyRegistry$Stub$Proxy
-com.android.internal.telephony.metrics.TelephonyMetrics
-com.android.internal.telephony.MultiSimSettingController
-com.android.internal.telephony.nano.CarrierIdProto$CarrierAttribute
-com.android.internal.telephony.nano.CarrierIdProto$CarrierId
-com.android.internal.telephony.nano.TelephonyProto$RilDataCall
-com.android.internal.telephony.nano.TelephonyProto$SmsSession$Event
-com.android.internal.telephony.nano.TelephonyProto$TelephonyCallSession$Event$RilCall
-com.android.internal.telephony.NitzStateMachine
-com.android.internal.telephony.PhoneConfigurationManager
-com.android.internal.telephony.PhoneFactory
-com.android.internal.telephony.PhoneSwitcher
-com.android.internal.telephony.ProxyController
-com.android.internal.telephony.RadioConfig
-com.android.internal.telephony.RIL
-com.android.internal.telephony.RILRequest
-com.android.internal.telephony.RilWakelockInfo
-com.android.internal.telephony.ServiceStateTracker
-com.android.internal.telephony.SimActivationTracker
-com.android.internal.telephony.SmsApplication
-com.android.internal.telephony.SmsBroadcastUndelivered
-com.android.internal.telephony.SmsStorageMonitor
-com.android.internal.telephony.SmsUsageMonitor
-com.android.internal.telephony.SubscriptionController
-com.android.internal.telephony.SubscriptionInfoUpdater
-com.android.internal.telephony.TelephonyComponentFactory
-com.android.internal.telephony.TelephonyDevController
-com.android.internal.telephony.TelephonyTester
-com.android.internal.telephony.uicc.AdnRecordCache
-com.android.internal.telephony.uicc.UiccCardApplication
-com.android.internal.telephony.uicc.UiccController
-com.android.internal.telephony.uicc.UiccProfile
-com.android.internal.telephony.uicc.UiccStateChangedLauncher
-com.android.internal.telephony.uicc.UsimFileHandler
-com.android.internal.telephony.uicc.VoiceMailConstants
-com.android.internal.util.LatencyTracker
-com.android.internal.util.StateMachine$SmHandler
-com.android.okhttp.OkHttpClient
-com.android.okhttp.okio.AsyncTimeout
-com.android.okhttp.okio.SegmentPool
-com.android.phone.ecc.nano.ProtobufEccData$CountryInfo
-com.android.phone.ecc.nano.ProtobufEccData$EccInfo
-com.android.server.sip.SipWakeupTimer
-com.android.server.SystemConfig
-dalvik.system.BaseDexClassLoader
-dalvik.system.BlockGuard
-dalvik.system.CloseGuard
-dalvik.system.RuntimeHooks
-dalvik.system.SocketTagger
-java.io.BufferedReader
-java.lang.AssertionError
-java.lang.Boolean
-java.lang.Byte
-java.lang.Character
-java.lang.CharSequence
-java.lang.Class
-java.lang.IllegalAccessException
-java.lang.IllegalStateException
-java.lang.NoSuchMethodException
-java.lang.NullPointerException
-java.lang.Object
-java.lang.Object[]
-java.lang.ref.FinalizerReference
-java.lang.Runnable
-java.lang.SecurityException
-java.lang.Short
-java.lang.String[]
-java.lang.System
-java.lang.Thread
-java.lang.Throwable
-java.lang.UnsatisfiedLinkError
-java.net.Inet6Address
-java.net.Socket
-java.net.SocketException
-java.nio.Bits
-java.nio.charset.Charset
-java.security.interfaces.RSAPrivateKey
-java.security.Provider
-java.util.Collections
-java.util.concurrent.Executor
-java.util.GregorianCalendar
-java.util.Locale
-java.util.Locale$NoImagePreloadHolder
-java.util.Scanner
-java.util.Set
-java.util.TimeZone
-javax.net.SocketFactory
-javax.net.ssl.HttpsURLConnection
-javax.net.ssl.HttpsURLConnection$NoPreloadHolder
-javax.net.ssl.SSLContext
-javax.net.ssl.SSLSessionContext
-javax.net.ssl.SSLSocketFactory
-libcore.io.Libcore
-libcore.io.Memory
-libcore.net.NetworkSecurityPolicy
-libcore.timezone.TimeZoneFinder
-org.apache.http.params.HttpParams
-sun.misc.Cleaner
-sun.nio.ch.FileChannelImpl
-sun.nio.ch.FileChannelImpl$Unmapper
-sun.nio.fs.UnixChannelFactory
-sun.security.jca.Providers
+Landroid/accounts/Account;
+Landroid/accounts/OnAccountsUpdateListener;
+Landroid/animation/LayoutTransition;
+Landroid/app/ActivityManager;
+Landroid/app/ActivityManager$OnUidImportanceListener;
+Landroid/app/ActivityTaskManager;
+Landroid/app/ActivityThread;
+Landroid/app/admin/DevicePolicyManager;
+Landroid/app/AlarmManager;
+Landroid/app/Application;
+Landroid/app/AppOpsManager;
+Landroid/app/backup/BackupManager;
+Landroid/app/ContextImpl;
+Landroid/app/INotificationManager;
+Landroid/app/Notification$BigPictureStyle;
+Landroid/app/Notification$BigTextStyle;
+Landroid/app/Notification$InboxStyle;
+Landroid/app/NotificationChannel;
+Landroid/app/NotificationChannelGroup;
+Landroid/app/NotificationManager;
+Landroid/app/PendingIntent;
+Landroid/app/PendingIntent$OnFinished;
+Landroid/app/QueuedWork;
+Landroid/app/ResourcesManager;
+Landroid/app/WallpaperManager;
+Landroid/app/WindowConfiguration;
+Landroid/bluetooth/BluetoothAdapter;
+Landroid/bluetooth/BluetoothDevice;
+Landroid/bluetooth/BluetoothProfile;
+Landroid/bluetooth/IBluetoothA2dp;
+Landroid/bluetooth/IBluetoothHeadsetPhone;
+Landroid/bluetooth/IBluetoothHidDevice;
+Landroid/bluetooth/IBluetoothHidHost;
+Landroid/bluetooth/IBluetoothMap;
+Landroid/bluetooth/IBluetoothPan;
+Landroid/bluetooth/IBluetoothPbap;
+Landroid/bluetooth/IBluetoothSap;
+Landroid/content/ClipboardManager$OnPrimaryClipChangedListener;
+Landroid/content/ComponentName;
+Landroid/content/ContentProvider$PipeDataWriter;
+Landroid/content/ContentResolver;
+Landroid/content/Context;
+Landroid/content/Intent;
+Landroid/content/pm/PackageManager$OnPermissionsChangedListener;
+Landroid/content/pm/VersionedPackage;
+Landroid/content/res/Configuration;
+Landroid/content/SharedPreferences$OnSharedPreferenceChangeListener;
+Landroid/database/CursorWindow;
+Landroid/database/sqlite/SQLiteCompatibilityWalFlags;
+Landroid/database/sqlite/SQLiteDatabase$CursorFactory;
+Landroid/database/sqlite/SQLiteGlobal;
+Landroid/database/sqlite/SQLiteTransactionListener;
+Landroid/ddm/DdmHandleAppName;
+Landroid/graphics/Bitmap;
+Landroid/graphics/Canvas;
+Landroid/graphics/drawable/AdaptiveIconDrawable;
+Landroid/graphics/drawable/ColorDrawable;
+Landroid/graphics/drawable/GradientDrawable;
+Landroid/graphics/drawable/Icon;
+Landroid/graphics/drawable/InsetDrawable;
+Landroid/graphics/drawable/RippleDrawable;
+Landroid/graphics/drawable/VectorDrawable$VGroup;
+Landroid/graphics/ImageDecoder;
+Landroid/graphics/Rect;
+Landroid/graphics/TemporaryBuffer;
+Landroid/hardware/biometrics/BiometricSourceType;
+Landroid/hardware/display/ColorDisplayManager$ColorDisplayManagerInternal;
+Landroid/hardware/display/DisplayManagerGlobal;
+Landroid/hardware/display/NightDisplayListener$Callback;
+Landroid/hardware/input/InputManager;
+Landroid/hardware/input/InputManager$InputDeviceListener;
+Landroid/hardware/SensorPrivacyManager;
+Landroid/hardware/SystemSensorManager;
+Landroid/icu/impl/OlsonTimeZone;
+Landroid/icu/text/BreakIterator;
+Landroid/icu/text/Collator;
+Landroid/icu/text/DateFormat$BooleanAttribute;
+Landroid/icu/text/DateTimePatternGenerator$DTPGflags;
+Landroid/icu/text/PluralRules$Operand;
+Landroid/icu/util/TimeZone;
+Landroid/location/GpsStatus$Listener;
+Landroid/location/LocationListener;
+Landroid/media/AudioManager;
+Landroid/media/MediaRouter;
+Landroid/media/PlayerBase;
+Landroid/media/session/MediaSessionManager;
+Landroid/net/apf/ApfCapabilities;
+Landroid/net/ConnectivityManager;
+Landroid/net/ConnectivityManager$OnNetworkActiveListener;
+Landroid/net/ConnectivityThread$Singleton;
+Landroid/net/IpConfiguration$IpAssignment;
+Landroid/net/IpConfiguration$ProxySettings;
+Landroid/net/IpPrefix;
+Landroid/net/LinkAddress;
+Landroid/net/LinkProperties;
+Landroid/net/Network;
+Landroid/net/NetworkCapabilities;
+Landroid/net/NetworkInfo;
+Landroid/net/NetworkInfo$State;
+Landroid/net/NetworkRequest;
+Landroid/net/NetworkRequest$Type;
+Landroid/net/RouteInfo;
+Landroid/net/StringNetworkSpecifier;
+Landroid/net/TrafficStats;
+Landroid/net/UidRange;
+Landroid/net/Uri$HierarchicalUri;
+Landroid/net/Uri$StringUri;
+Landroid/net/wifi/WifiManager;
+Landroid/net/wifi/WifiManager$SoftApCallback;
+Landroid/os/AsyncResult;
+Landroid/os/AsyncTask;
+Landroid/os/BinderProxy;
+Landroid/os/Bundle;
+Landroid/os/DeadObjectException;
+Landroid/os/Environment;
+Landroid/os/FileObserver;
+Landroid/os/Handler;
+Landroid/os/IDeviceIdleController;
+Landroid/os/LocaleList;
+Landroid/os/Looper;
+Landroid/os/Message;
+Landroid/os/ParcelUuid;
+Landroid/os/Process;
+Landroid/os/RecoverySystem;
+Landroid/os/ServiceManager;
+Landroid/os/storage/StorageManager;
+Landroid/os/StrictMode;
+Landroid/os/Trace;
+Landroid/os/WorkSource;
+Landroid/os/WorkSource$WorkChain;
+Landroid/permission/PermissionManager;
+Landroid/provider/FontsContract;
+Landroid/provider/Settings$SettingNotFoundException;
+Landroid/renderscript/RenderScriptCacheDir;
+Landroid/security/IKeyChainService;
+Landroid/security/keystore/AndroidKeyStoreProvider;
+Landroid/security/net/config/ApplicationConfig;
+Landroid/security/net/config/SystemCertificateSource$NoPreloadHolder;
+Landroid/telecom/PhoneAccountHandle;
+Landroid/telephony/AnomalyReporter;
+Landroid/telephony/CellSignalStrengthCdma;
+Landroid/telephony/CellSignalStrengthGsm;
+Landroid/telephony/CellSignalStrengthLte;
+Landroid/telephony/CellSignalStrengthNr;
+Landroid/telephony/CellSignalStrengthTdscdma;
+Landroid/telephony/CellSignalStrengthWcdma;
+Landroid/telephony/DataSpecificRegistrationInfo;
+Landroid/telephony/emergency/EmergencyNumber;
+Landroid/telephony/ims/ImsMmTelManager$CapabilityCallback$CapabilityBinder;
+Landroid/telephony/ims/ImsMmTelManager$RegistrationCallback$RegistrationBinder;
+Landroid/telephony/ims/ImsReasonInfo;
+Landroid/telephony/ims/ProvisioningManager$Callback$CallbackBinder;
+Landroid/telephony/ModemActivityInfo;
+Landroid/telephony/ModemInfo;
+Landroid/telephony/NetworkRegistrationInfo;
+Landroid/telephony/NetworkService;
+Landroid/telephony/TelephonyManager;
+Landroid/telephony/VoiceSpecificRegistrationInfo;
+Landroid/text/format/DateFormat;
+Landroid/text/method/SingleLineTransformationMethod;
+Landroid/text/Selection$MemoryTextWatcher;
+Landroid/text/SpanWatcher;
+Landroid/text/style/AlignmentSpan;
+Landroid/text/style/CharacterStyle;
+Landroid/text/style/LeadingMarginSpan;
+Landroid/text/style/LineBackgroundSpan;
+Landroid/text/style/LineHeightSpan;
+Landroid/text/style/MetricAffectingSpan;
+Landroid/text/style/ReplacementSpan;
+Landroid/text/style/SuggestionSpan;
+Landroid/text/style/TabStopSpan;
+Landroid/text/TextUtils;
+Landroid/text/TextWatcher;
+Landroid/transition/ChangeClipBounds;
+Landroid/transition/ChangeImageTransform;
+Landroid/transition/ChangeTransform;
+Landroid/util/ArrayMap;
+Landroid/util/ArraySet;
+Landroid/util/DisplayMetrics;
+Landroid/util/EventLog;
+Landroid/util/Log;
+Landroid/util/Patterns;
+Landroid/view/AbsSavedState$1;
+Landroid/view/accessibility/AccessibilityManager;
+Landroid/view/accessibility/AccessibilityManager$AccessibilityServicesStateChangeListener;
+Landroid/view/accessibility/AccessibilityManager$TouchExplorationStateChangeListener;
+Landroid/view/accessibility/AccessibilityNodeIdManager;
+Landroid/view/autofill/AutofillManager;
+Landroid/view/autofill/Helper;
+Landroid/view/Choreographer;
+Landroid/view/inputmethod/InputMethodManager;
+Landroid/view/IWindowManager;
+Landroid/view/PointerIcon;
+Landroid/view/RemoteAnimationAdapter;
+Landroid/view/ThreadedRenderer;
+Landroid/view/View;
+Landroid/view/View$OnHoverListener;
+Landroid/view/ViewRootImpl;
+Landroid/view/ViewStub;
+Landroid/view/ViewStub$OnInflateListener;
+Landroid/view/ViewTreeObserver;
+Landroid/view/WindowManager$LayoutParams;
+Landroid/view/WindowManagerGlobal;
+Landroid/widget/ActionMenuPresenter$OverflowMenuButton;
+Landroid/widget/ActionMenuView;
+Landroid/widget/Button;
+Landroid/widget/CheckBox;
+Landroid/widget/FrameLayout;
+Landroid/widget/ImageButton;
+Landroid/widget/ImageView;
+Landroid/widget/LinearLayout;
+Landroid/widget/RelativeLayout;
+Landroid/widget/SeekBar;
+Landroid/widget/Space;
+Landroid/widget/TextView;
+Landroid/widget/Toolbar;
+[B
+Lcom/android/ims/ImsManager;
+Lcom/android/internal/logging/MetricsLogger;
+Lcom/android/internal/os/BackgroundThread;
+Lcom/android/internal/os/BinderInternal;
+Lcom/android/internal/os/BinderInternal$BinderProxyLimitListener;
+Lcom/android/internal/os/RuntimeInit;
+Lcom/android/internal/os/SomeArgs;
+Lcom/android/internal/policy/DecorView;
+Lcom/android/internal/statusbar/IStatusBarService;
+Lcom/android/internal/telephony/AppSmsManager;
+Landroid/telephony/CallerInfoAsyncQuery$OnQueryCompleteListener;
+Lcom/android/internal/telephony/CarrierActionAgent;
+Lcom/android/internal/telephony/cat/CatService;
+Lcom/android/internal/telephony/cat/IconLoader;
+Lcom/android/internal/telephony/cat/RilMessageDecoder;
+Lcom/android/internal/telephony/cdma/CdmaSubscriptionSourceManager;
+Lcom/android/internal/telephony/cdma/EriManager;
+Lcom/android/internal/telephony/CellularNetworkValidator;
+Lcom/android/internal/telephony/CommandException;
+Lcom/android/internal/telephony/dataconnection/DataConnection$DcActivatingState;
+Lcom/android/internal/telephony/dataconnection/DataConnection$DcActiveState;
+Lcom/android/internal/telephony/dataconnection/DataConnection$DcInactiveState;
+Lcom/android/internal/telephony/dataconnection/DataEnabledSettings;
+Lcom/android/internal/telephony/dataconnection/DcTracker;
+Lcom/android/internal/telephony/euicc/EuiccCardController;
+Lcom/android/internal/telephony/euicc/EuiccController;
+Lcom/android/internal/telephony/GsmAlphabet;
+Lcom/android/internal/telephony/GsmCdmaCallTracker;
+Lcom/android/internal/telephony/GsmCdmaPhone;
+Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;
+Lcom/android/internal/telephony/IccSmsInterfaceManager;
+Lcom/android/internal/telephony/ims/ImsResolver;
+Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker;
+Lcom/android/internal/telephony/imsphone/ImsPhone;
+Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;
+Lcom/android/internal/telephony/ims/RcsMessageStoreController;
+Lcom/android/internal/telephony/IntentBroadcaster;
+Lcom/android/internal/telephony/ITelephonyRegistry$Stub$Proxy;
+Lcom/android/internal/telephony/metrics/TelephonyMetrics;
+Lcom/android/internal/telephony/MultiSimSettingController;
+Lcom/android/internal/telephony/nano/CarrierIdProto$CarrierAttribute;
+Lcom/android/internal/telephony/nano/CarrierIdProto$CarrierId;
+Lcom/android/internal/telephony/nano/TelephonyProto$RilDataCall;
+Lcom/android/internal/telephony/nano/TelephonyProto$SmsSession$Event;
+Lcom/android/internal/telephony/nano/TelephonyProto$TelephonyCallSession$Event$RilCall;
+Lcom/android/internal/telephony/NitzStateMachine;
+Lcom/android/internal/telephony/PhoneConfigurationManager;
+Lcom/android/internal/telephony/PhoneFactory;
+Lcom/android/internal/telephony/PhoneSwitcher;
+Lcom/android/internal/telephony/ProxyController;
+Lcom/android/internal/telephony/RadioConfig;
+Lcom/android/internal/telephony/RIL;
+Lcom/android/internal/telephony/RILRequest;
+Lcom/android/internal/telephony/RilWakelockInfo;
+Lcom/android/internal/telephony/ServiceStateTracker;
+Lcom/android/internal/telephony/SimActivationTracker;
+Lcom/android/internal/telephony/SmsApplication;
+Lcom/android/internal/telephony/SmsBroadcastUndelivered;
+Lcom/android/internal/telephony/SmsStorageMonitor;
+Lcom/android/internal/telephony/SmsUsageMonitor;
+Lcom/android/internal/telephony/SubscriptionController;
+Lcom/android/internal/telephony/SubscriptionInfoUpdater;
+Lcom/android/internal/telephony/TelephonyComponentFactory;
+Lcom/android/internal/telephony/TelephonyDevController;
+Lcom/android/internal/telephony/TelephonyTester;
+Lcom/android/internal/telephony/uicc/AdnRecordCache;
+Lcom/android/internal/telephony/uicc/UiccCardApplication;
+Lcom/android/internal/telephony/uicc/UiccController;
+Lcom/android/internal/telephony/uicc/UiccProfile;
+Lcom/android/internal/telephony/uicc/UiccStateChangedLauncher;
+Lcom/android/internal/telephony/uicc/UsimFileHandler;
+Lcom/android/internal/telephony/uicc/VoiceMailConstants;
+Lcom/android/internal/util/LatencyTracker;
+Lcom/android/internal/util/StateMachine$SmHandler;
+Lcom/android/okhttp/OkHttpClient;
+Lcom/android/okhttp/okio/AsyncTimeout;
+Lcom/android/okhttp/okio/SegmentPool;
+Lcom/android/phone/ecc/nano/ProtobufEccData$CountryInfo;
+Lcom/android/phone/ecc/nano/ProtobufEccData$EccInfo;
+Lcom/android/server/sip/SipWakeupTimer;
+Lcom/android/server/SystemConfig;
+Ldalvik/system/BaseDexClassLoader;
+Ldalvik/system/BlockGuard;
+Ldalvik/system/CloseGuard;
+Ldalvik/system/RuntimeHooks;
+Ldalvik/system/SocketTagger;
+Ljava/io/BufferedReader;
+Ljava/lang/AssertionError;
+Ljava/lang/Boolean;
+Ljava/lang/Byte;
+Ljava/lang/Character;
+Ljava/lang/CharSequence;
+Ljava/lang/Class;
+Ljava/lang/IllegalAccessException;
+Ljava/lang/IllegalStateException;
+Ljava/lang/NoSuchMethodException;
+Ljava/lang/NullPointerException;
+Ljava/lang/Object;
+[Ljava/lang/Object;
+Ljava/lang/ref/FinalizerReference;
+Ljava/lang/Runnable;
+Ljava/lang/SecurityException;
+Ljava/lang/Short;
+[Ljava/lang/String;
+Ljava/lang/System;
+Ljava/lang/Thread;
+Ljava/lang/Throwable;
+Ljava/lang/UnsatisfiedLinkError;
+Ljava/net/Inet6Address;
+Ljava/net/Socket;
+Ljava/net/SocketException;
+Ljava/nio/Bits;
+Ljava/nio/charset/Charset;
+Ljava/security/interfaces/RSAPrivateKey;
+Ljava/security/Provider;
+Ljava/util/Collections;
+Ljava/util/concurrent/Executor;
+Ljava/util/GregorianCalendar;
+Ljava/util/Locale;
+Ljava/util/Locale$NoImagePreloadHolder;
+Ljava/util/Scanner;
+Ljava/util/Set;
+Ljava/util/TimeZone;
+Ljavax/net/SocketFactory;
+Ljavax/net/ssl/HttpsURLConnection;
+Ljavax/net/ssl/HttpsURLConnection$NoPreloadHolder;
+Ljavax/net/ssl/SSLContext;
+Ljavax/net/ssl/SSLSessionContext;
+Ljavax/net/ssl/SSLSocketFactory;
+Llibcore/io/Libcore;
+Llibcore/io/Memory;
+Llibcore/net/NetworkSecurityPolicy;
+Llibcore/timezone/TimeZoneFinder;
+Lorg/apache/http/params/HttpParams;
+Lsun/misc/Cleaner;
+Lsun/nio/ch/FileChannelImpl;
+Lsun/nio/ch/FileChannelImpl$Unmapper;
+Lsun/nio/fs/UnixChannelFactory;
+Lsun/security/jca/Providers;
diff --git a/core/api/current.txt b/core/api/current.txt
index 0eb3b49..8e91ddb 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -21,7 +21,6 @@
     field public static final String ACTIVITY_RECOGNITION = "android.permission.ACTIVITY_RECOGNITION";
     field public static final String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
     field public static final String ANSWER_PHONE_CALLS = "android.permission.ANSWER_PHONE_CALLS";
-    field public static final String BACKGROUND_CAMERA = "android.permission.BACKGROUND_CAMERA";
     field public static final String BATTERY_STATS = "android.permission.BATTERY_STATS";
     field public static final String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
     field public static final String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
@@ -134,7 +133,6 @@
     field public static final String RECEIVE_SMS = "android.permission.RECEIVE_SMS";
     field public static final String RECEIVE_WAP_PUSH = "android.permission.RECEIVE_WAP_PUSH";
     field public static final String RECORD_AUDIO = "android.permission.RECORD_AUDIO";
-    field public static final String RECORD_BACKGROUND_AUDIO = "android.permission.RECORD_BACKGROUND_AUDIO";
     field public static final String REORDER_TASKS = "android.permission.REORDER_TASKS";
     field public static final String REQUEST_COMPANION_PROFILE_WATCH = "android.permission.REQUEST_COMPANION_PROFILE_WATCH";
     field public static final String REQUEST_COMPANION_RUN_IN_BACKGROUND = "android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND";
@@ -507,6 +505,7 @@
     field public static final int dashGap = 16843175; // 0x10101a7
     field public static final int dashWidth = 16843174; // 0x10101a6
     field public static final int data = 16842798; // 0x101002e
+    field public static final int dataExtractionRules = 16844350; // 0x101063e
     field public static final int datePickerDialogTheme = 16843948; // 0x10104ac
     field public static final int datePickerMode = 16843955; // 0x10104b3
     field public static final int datePickerStyle = 16843612; // 0x101035c
@@ -5610,6 +5609,7 @@
     field public static final int DEFAULT_LIGHTS = 4; // 0x4
     field public static final int DEFAULT_SOUND = 1; // 0x1
     field public static final int DEFAULT_VIBRATE = 2; // 0x2
+    field public static final String EXTRA_ANSWER_COLOR = "android.answerColor";
     field public static final String EXTRA_ANSWER_INTENT = "android.answerIntent";
     field public static final String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
     field public static final String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
@@ -5621,6 +5621,7 @@
     field public static final String EXTRA_COLORIZED = "android.colorized";
     field public static final String EXTRA_COMPACT_ACTIONS = "android.compactActions";
     field public static final String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
+    field public static final String EXTRA_DECLINE_COLOR = "android.declineColor";
     field public static final String EXTRA_DECLINE_INTENT = "android.declineIntent";
     field public static final String EXTRA_HANG_UP_INTENT = "android.hangUpIntent";
     field public static final String EXTRA_HISTORIC_MESSAGES = "android.messages.historic";
@@ -5908,6 +5909,8 @@
     method @NonNull public static android.app.Notification.CallStyle forIncomingCall(@NonNull android.app.Person, @NonNull android.app.PendingIntent, @NonNull android.app.PendingIntent);
     method @NonNull public static android.app.Notification.CallStyle forOngoingCall(@NonNull android.app.Person, @NonNull android.app.PendingIntent);
     method @NonNull public static android.app.Notification.CallStyle forScreeningCall(@NonNull android.app.Person, @NonNull android.app.PendingIntent, @NonNull android.app.PendingIntent);
+    method @NonNull public android.app.Notification.CallStyle setAnswerButtonColorHint(@ColorInt int);
+    method @NonNull public android.app.Notification.CallStyle setDeclineButtonColorHint(@ColorInt int);
     method @NonNull public android.app.Notification.CallStyle setVerificationIcon(@Nullable android.graphics.drawable.Icon);
     method @NonNull public android.app.Notification.CallStyle setVerificationText(@Nullable CharSequence);
   }
@@ -6265,14 +6268,14 @@
     method public static android.app.PendingIntent getActivities(android.content.Context, int, @NonNull android.content.Intent[], int, @Nullable android.os.Bundle);
     method public static android.app.PendingIntent getActivity(android.content.Context, int, android.content.Intent, int);
     method public static android.app.PendingIntent getActivity(android.content.Context, int, @NonNull android.content.Intent, int, @Nullable android.os.Bundle);
-    method public static android.app.PendingIntent getBroadcast(android.content.Context, int, android.content.Intent, int);
-    method @Nullable public String getCreatorPackage();
+    method public static android.app.PendingIntent getBroadcast(android.content.Context, int, @NonNull android.content.Intent, int);
+    method @NonNull public String getCreatorPackage();
     method public int getCreatorUid();
-    method @Nullable public android.os.UserHandle getCreatorUserHandle();
+    method @NonNull public android.os.UserHandle getCreatorUserHandle();
     method public static android.app.PendingIntent getForegroundService(android.content.Context, int, @NonNull android.content.Intent, int);
-    method public android.content.IntentSender getIntentSender();
+    method @NonNull public android.content.IntentSender getIntentSender();
     method public static android.app.PendingIntent getService(android.content.Context, int, @NonNull android.content.Intent, int);
-    method @Deprecated public String getTargetPackage();
+    method @Deprecated @NonNull public String getTargetPackage();
     method public boolean isActivity();
     method public boolean isBroadcast();
     method public boolean isForegroundService();
@@ -6807,14 +6810,18 @@
   public final class WallpaperColors implements android.os.Parcelable {
     ctor public WallpaperColors(android.os.Parcel);
     ctor public WallpaperColors(@NonNull android.graphics.Color, @Nullable android.graphics.Color, @Nullable android.graphics.Color);
+    ctor public WallpaperColors(@NonNull android.graphics.Color, @Nullable android.graphics.Color, @Nullable android.graphics.Color, int);
     method public int describeContents();
     method public static android.app.WallpaperColors fromBitmap(@NonNull android.graphics.Bitmap);
     method public static android.app.WallpaperColors fromDrawable(android.graphics.drawable.Drawable);
+    method public int getColorHints();
     method @NonNull public android.graphics.Color getPrimaryColor();
     method @Nullable public android.graphics.Color getSecondaryColor();
     method @Nullable public android.graphics.Color getTertiaryColor();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.WallpaperColors> CREATOR;
+    field public static final int HINT_SUPPORTS_DARK_TEXT = 1; // 0x1
+    field public static final int HINT_SUPPORTS_DARK_THEME = 2; // 0x2
   }
 
   public final class WallpaperInfo implements android.os.Parcelable {
@@ -8371,7 +8378,9 @@
     method protected android.view.View getDefaultView();
     method protected android.view.View getErrorView();
     method protected void prepareView(android.view.View);
+    method public void resetColorResources();
     method public void setAppWidget(int, android.appwidget.AppWidgetProviderInfo);
+    method public void setColorResources(@NonNull android.util.SparseIntArray);
     method public void setCurrentSize(@NonNull android.graphics.PointF);
     method public void setExecutor(java.util.concurrent.Executor);
     method public void setOnLightBackground(boolean);
@@ -8452,7 +8461,7 @@
     method public int describeContents();
     method public final android.os.UserHandle getProfile();
     method @NonNull public android.content.pm.ActivityInfo getProviderInfo();
-    method @Nullable public final String loadDescription(@NonNull android.content.Context);
+    method @Nullable public final CharSequence loadDescription(@NonNull android.content.Context);
     method public final android.graphics.drawable.Drawable loadIcon(@NonNull android.content.Context, int);
     method public final String loadLabel(android.content.pm.PackageManager);
     method public final android.graphics.drawable.Drawable loadPreviewImage(@NonNull android.content.Context, int);
@@ -8470,7 +8479,7 @@
     field public static final int WIDGET_FEATURE_RECONFIGURABLE = 1; // 0x1
     field public int autoAdvanceViewId;
     field public android.content.ComponentName configure;
-    field @IdRes public int descriptionResource;
+    field @IdRes public int descriptionRes;
     field public int icon;
     field public int initialKeyguardLayout;
     field public int initialLayout;
@@ -9734,7 +9743,7 @@
   public interface DeviceFilter<D extends android.os.Parcelable> extends android.os.Parcelable {
   }
 
-  public class DeviceNotAssociatedException extends java.lang.Exception {
+  public class DeviceNotAssociatedException extends java.lang.RuntimeException {
   }
 
   public final class WifiDeviceFilter implements android.companion.DeviceFilter<android.net.wifi.ScanResult> {
@@ -10238,6 +10247,7 @@
     field public static final String SYNC_EXTRAS_MANUAL = "force";
     field public static final String SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS = "deletions_override";
     field public static final String SYNC_EXTRAS_REQUIRE_CHARGING = "require_charging";
+    field public static final String SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB = "schedule_as_expedited_job";
     field public static final String SYNC_EXTRAS_UPLOAD = "upload";
     field public static final int SYNC_OBSERVER_TYPE_ACTIVE = 4; // 0x4
     field public static final int SYNC_OBSERVER_TYPE_PENDING = 2; // 0x2
@@ -10381,7 +10391,7 @@
     method public abstract void grantUriPermission(String, android.net.Uri, int);
     method public abstract boolean isDeviceProtectedStorage();
     method public boolean isRestricted();
-    method public static boolean isUiContext(@NonNull android.content.Context);
+    method public boolean isUiContext();
     method public abstract boolean moveDatabaseFrom(android.content.Context, String);
     method public abstract boolean moveSharedPreferencesFrom(android.content.Context, String);
     method @NonNull public final android.content.res.TypedArray obtainStyledAttributes(@NonNull @StyleableRes int[]);
@@ -11560,6 +11570,7 @@
     method public android.content.SyncRequest.Builder setManual(boolean);
     method public android.content.SyncRequest.Builder setNoRetry(boolean);
     method public android.content.SyncRequest.Builder setRequiresCharging(boolean);
+    method @NonNull public android.content.SyncRequest.Builder setScheduleAsExpeditedJob(boolean);
     method public android.content.SyncRequest.Builder setSyncAdapter(android.accounts.Account, String);
     method public android.content.SyncRequest.Builder syncOnce();
     method public android.content.SyncRequest.Builder syncPeriodic(long, long);
@@ -12554,7 +12565,6 @@
     field public static final String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
     field public static final String FEATURE_WIFI_PASSPOINT = "android.hardware.wifi.passpoint";
     field public static final String FEATURE_WIFI_RTT = "android.hardware.wifi.rtt";
-    field public static final int FLAG_PERMISSION_ALLOWLIST_ROLE = 8; // 0x8
     field public static final int FLAG_PERMISSION_WHITELIST_INSTALLER = 2; // 0x2
     field public static final int FLAG_PERMISSION_WHITELIST_SYSTEM = 1; // 0x1
     field public static final int FLAG_PERMISSION_WHITELIST_UPGRADE = 4; // 0x4
@@ -12693,7 +12703,6 @@
     field public static final int FLAG_HARD_RESTRICTED = 4; // 0x4
     field public static final int FLAG_IMMUTABLY_RESTRICTED = 16; // 0x10
     field public static final int FLAG_INSTALLED = 1073741824; // 0x40000000
-    field public static final int FLAG_INSTALLER_EXEMPT_IGNORED = 32; // 0x20
     field public static final int FLAG_SOFT_RESTRICTED = 8; // 0x8
     field public static final int PROTECTION_DANGEROUS = 1; // 0x1
     field public static final int PROTECTION_FLAG_APPOP = 64; // 0x40
@@ -12893,6 +12902,7 @@
     method public void reportShortcutUsed(String);
     method public boolean requestPinShortcut(@NonNull android.content.pm.ShortcutInfo, @Nullable android.content.IntentSender);
     method public boolean setDynamicShortcuts(@NonNull java.util.List<android.content.pm.ShortcutInfo>);
+    method public void updateShortcutVisibility(@NonNull String, @Nullable byte[], boolean);
     method 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
@@ -18559,6 +18569,23 @@
 
 package android.hardware.display {
 
+  public final class DeviceProductInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getConnectionToSinkType();
+    method public int getManufactureWeek();
+    method public int getManufactureYear();
+    method @NonNull public String getManufacturerPnpId();
+    method public int getModelYear();
+    method @Nullable public String getName();
+    method @NonNull public String getProductId();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int CONNECTION_TO_SINK_BUILT_IN = 1; // 0x1
+    field public static final int CONNECTION_TO_SINK_DIRECT = 2; // 0x2
+    field public static final int CONNECTION_TO_SINK_TRANSITIVE = 3; // 0x3
+    field public static final int CONNECTION_TO_SINK_UNKNOWN = 0; // 0x0
+    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.display.DeviceProductInfo> CREATOR;
+  }
+
   public final class DisplayManager {
     method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, int, int, int, @Nullable android.view.Surface, int);
     method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, int, int, int, @Nullable android.view.Surface, int, @Nullable android.hardware.display.VirtualDisplay.Callback, @Nullable android.os.Handler);
@@ -18887,6 +18914,7 @@
   public abstract class AbstractInputMethodService extends android.app.Service implements android.view.KeyEvent.Callback {
     ctor public AbstractInputMethodService();
     method public android.view.KeyEvent.DispatcherState getKeyDispatcherState();
+    method public final boolean isUiContext();
     method public final android.os.IBinder onBind(android.content.Intent);
     method public abstract android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodImpl onCreateInputMethodInterface();
     method public abstract android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface();
@@ -19283,8 +19311,8 @@
     method @NonNull public android.location.GnssAntennaInfo.Builder setSignalGainCorrections(@Nullable android.location.GnssAntennaInfo.SphericalCorrections);
   }
 
-  @Deprecated public static interface GnssAntennaInfo.Listener {
-    method @Deprecated public void onGnssAntennaInfoReceived(@NonNull java.util.List<android.location.GnssAntennaInfo>);
+  public static interface GnssAntennaInfo.Listener {
+    method public void onGnssAntennaInfoReceived(@NonNull java.util.List<android.location.GnssAntennaInfo>);
   }
 
   public static final class GnssAntennaInfo.PhaseCenterOffset implements android.os.Parcelable {
@@ -19652,6 +19680,7 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void addProximityAlert(double, double, float, long, @NonNull android.app.PendingIntent);
     method public void addTestProvider(@NonNull String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
     method public void addTestProvider(@NonNull String, @NonNull android.location.provider.ProviderProperties);
+    method public void addTestProvider(@NonNull String, @NonNull android.location.provider.ProviderProperties, @NonNull java.util.Set<java.lang.String>);
     method @Deprecated public void clearTestProviderEnabled(@NonNull String);
     method @Deprecated public void clearTestProviderLocation(@NonNull String);
     method @Deprecated public void clearTestProviderStatus(@NonNull String);
@@ -19672,7 +19701,7 @@
     method public boolean hasProvider(@NonNull String);
     method public boolean isLocationEnabled();
     method public boolean isProviderEnabled(@NonNull String);
-    method @Deprecated public boolean registerAntennaInfoListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssAntennaInfo.Listener);
+    method public boolean registerAntennaInfoListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssAntennaInfo.Listener);
     method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback);
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback, @Nullable android.os.Handler);
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
@@ -19709,13 +19738,11 @@
     method public void setTestProviderEnabled(@NonNull String, boolean);
     method public void setTestProviderLocation(@NonNull String, @NonNull android.location.Location);
     method @Deprecated public void setTestProviderStatus(@NonNull String, int, @Nullable android.os.Bundle, long);
-    method @Deprecated public void unregisterAntennaInfoListener(@NonNull android.location.GnssAntennaInfo.Listener);
+    method public void unregisterAntennaInfoListener(@NonNull android.location.GnssAntennaInfo.Listener);
     method public void unregisterGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback);
     method public void unregisterGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback);
     method public void unregisterGnssStatusCallback(@NonNull android.location.GnssStatus.Callback);
-    field public static final String ACTION_GNSS_ANTENNA_INFOS_CHANGED = "android.location.action.GNSS_ANTENNA_INFOS_CHANGED";
     field public static final String ACTION_GNSS_CAPABILITIES_CHANGED = "android.location.action.GNSS_CAPABILITIES_CHANGED";
-    field public static final String EXTRA_GNSS_ANTENNA_INFOS = "android.location.extra.GNSS_ANTENNA_INFOS";
     field public static final String EXTRA_GNSS_CAPABILITIES = "android.location.extra.GNSS_CAPABILITIES";
     field public static final String EXTRA_LOCATION_ENABLED = "android.location.extra.LOCATION_ENABLED";
     field public static final String EXTRA_PROVIDER_ENABLED = "android.location.extra.PROVIDER_ENABLED";
@@ -19858,7 +19885,6 @@
     method public int getFlags();
     method public int getUsage();
     method public int getVolumeControlStream();
-    method @NonNull public static String usageToString(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ALLOW_CAPTURE_BY_ALL = 1; // 0x1
     field public static final int ALLOW_CAPTURE_BY_NONE = 3; // 0x3
@@ -20274,6 +20300,10 @@
     field @NonNull public static final android.media.AudioMetadata.Key<java.lang.Integer> KEY_BIT_WIDTH;
     field @NonNull public static final android.media.AudioMetadata.Key<java.lang.Integer> KEY_CHANNEL_MASK;
     field @NonNull public static final android.media.AudioMetadata.Key<java.lang.String> KEY_MIME;
+    field @NonNull public static final android.media.AudioMetadata.Key<java.lang.Integer> KEY_PRESENTATION_CONTENT_CLASSIFIER;
+    field @NonNull public static final android.media.AudioMetadata.Key<java.lang.Integer> KEY_PRESENTATION_ID;
+    field @NonNull public static final android.media.AudioMetadata.Key<java.lang.String> KEY_PRESENTATION_LANGUAGE;
+    field @NonNull public static final android.media.AudioMetadata.Key<java.lang.Integer> KEY_PROGRAM_ID;
     field @NonNull public static final android.media.AudioMetadata.Key<java.lang.Integer> KEY_SAMPLE_RATE;
   }
 
@@ -20328,6 +20358,15 @@
     method public boolean hasAudioDescription();
     method public boolean hasDialogueEnhancement();
     method public boolean hasSpokenSubtitles();
+    field public static final int CONTENT_COMMENTARY = 5; // 0x5
+    field public static final int CONTENT_DIALOG = 4; // 0x4
+    field public static final int CONTENT_EMERGENCY = 6; // 0x6
+    field public static final int CONTENT_HEARING_IMPAIRED = 3; // 0x3
+    field public static final int CONTENT_MAIN = 0; // 0x0
+    field public static final int CONTENT_MUSIC_AND_EFFECTS = 1; // 0x1
+    field public static final int CONTENT_UNKNOWN = -1; // 0xffffffff
+    field public static final int CONTENT_VISUALLY_IMPAIRED = 2; // 0x2
+    field public static final int CONTENT_VOICEOVER = 7; // 0x7
     field public static final int MASTERED_FOR_3D = 3; // 0x3
     field public static final int MASTERED_FOR_HEADPHONE = 4; // 0x4
     field public static final int MASTERED_FOR_STEREO = 1; // 0x1
@@ -21291,8 +21330,8 @@
   public static final class MediaCodecInfo.AudioCapabilities {
     method public android.util.Range<java.lang.Integer> getBitrateRange();
     method @NonNull public android.util.Range<java.lang.Integer>[] getInputChannelCountRanges();
-    method public int getMaxInputChannelCount();
-    method public int getMinInputChannelCount();
+    method @IntRange(from=1, to=255) public int getMaxInputChannelCount();
+    method @IntRange(from=1, to=255) public int getMinInputChannelCount();
     method public android.util.Range<java.lang.Integer>[] getSupportedSampleRateRanges();
     method public int[] getSupportedSampleRates();
     method public boolean isSampleRateSupported(int);
@@ -22140,6 +22179,14 @@
     field public static final String KEY_TILE_HEIGHT = "tile-height";
     field public static final String KEY_TILE_WIDTH = "tile-width";
     field public static final String KEY_TRACK_ID = "track-id";
+    field public static final String KEY_VIDEO_QP_B_MAX = "video-qp-b-max";
+    field public static final String KEY_VIDEO_QP_B_MIN = "video-qp-b-min";
+    field public static final String KEY_VIDEO_QP_I_MAX = "video-qp-i-max";
+    field public static final String KEY_VIDEO_QP_I_MIN = "video-qp-i-min";
+    field public static final String KEY_VIDEO_QP_MAX = "video-qp-max";
+    field public static final String KEY_VIDEO_QP_MIN = "video-qp-min";
+    field public static final String KEY_VIDEO_QP_P_MAX = "video-qp-p-max";
+    field public static final String KEY_VIDEO_QP_P_MIN = "video-qp-p-min";
     field public static final String KEY_WIDTH = "width";
     field public static final String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
     field public static final String MIMETYPE_AUDIO_AC3 = "audio/ac3";
@@ -24741,7 +24788,7 @@
     method @NonNull public java.util.List<android.media.session.MediaController> getActiveSessions(@Nullable android.content.ComponentName);
     method @NonNull public java.util.List<android.media.Session2Token> getSession2Tokens();
     method public boolean isTrustedForMediaControl(@NonNull android.media.session.MediaSessionManager.RemoteUserInfo);
-    method public void notifySession2Created(@NonNull android.media.Session2Token);
+    method @Deprecated public void notifySession2Created(@NonNull android.media.Session2Token);
     method public void removeOnActiveSessionsChangedListener(@NonNull android.media.session.MediaSessionManager.OnActiveSessionsChangedListener);
     method public void removeOnSession2TokensChangedListener(@NonNull android.media.session.MediaSessionManager.OnSession2TokensChangedListener);
   }
@@ -25808,161 +25855,6 @@
 
 package android.net {
 
-  public class CaptivePortal implements android.os.Parcelable {
-    method public int describeContents();
-    method public void ignoreNetwork();
-    method public void reportCaptivePortalDismissed();
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortal> CREATOR;
-  }
-
-  public class ConnectivityDiagnosticsManager {
-    method public void registerConnectivityDiagnosticsCallback(@NonNull android.net.NetworkRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback);
-    method public void unregisterConnectivityDiagnosticsCallback(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback);
-  }
-
-  public abstract static class ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback {
-    ctor public ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback();
-    method public void onConnectivityReportAvailable(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityReport);
-    method public void onDataStallSuspected(@NonNull android.net.ConnectivityDiagnosticsManager.DataStallReport);
-    method public void onNetworkConnectivityReported(@NonNull android.net.Network, boolean);
-  }
-
-  public static final class ConnectivityDiagnosticsManager.ConnectivityReport implements android.os.Parcelable {
-    ctor public ConnectivityDiagnosticsManager.ConnectivityReport(@NonNull android.net.Network, long, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkCapabilities, @NonNull android.os.PersistableBundle);
-    method public int describeContents();
-    method @NonNull public android.os.PersistableBundle getAdditionalInfo();
-    method @NonNull public android.net.LinkProperties getLinkProperties();
-    method @NonNull public android.net.Network getNetwork();
-    method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities();
-    method public long getReportTimestamp();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.ConnectivityDiagnosticsManager.ConnectivityReport> CREATOR;
-    field public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK = "networkProbesAttempted";
-    field public static final String KEY_NETWORK_PROBES_SUCCEEDED_BITMASK = "networkProbesSucceeded";
-    field public static final String KEY_NETWORK_VALIDATION_RESULT = "networkValidationResult";
-    field public static final int NETWORK_PROBE_DNS = 4; // 0x4
-    field public static final int NETWORK_PROBE_FALLBACK = 32; // 0x20
-    field public static final int NETWORK_PROBE_HTTP = 8; // 0x8
-    field public static final int NETWORK_PROBE_HTTPS = 16; // 0x10
-    field public static final int NETWORK_PROBE_PRIVATE_DNS = 64; // 0x40
-    field public static final int NETWORK_VALIDATION_RESULT_INVALID = 0; // 0x0
-    field public static final int NETWORK_VALIDATION_RESULT_PARTIALLY_VALID = 2; // 0x2
-    field public static final int NETWORK_VALIDATION_RESULT_SKIPPED = 3; // 0x3
-    field public static final int NETWORK_VALIDATION_RESULT_VALID = 1; // 0x1
-  }
-
-  public static final class ConnectivityDiagnosticsManager.DataStallReport implements android.os.Parcelable {
-    ctor public ConnectivityDiagnosticsManager.DataStallReport(@NonNull android.net.Network, long, int, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkCapabilities, @NonNull android.os.PersistableBundle);
-    method public int describeContents();
-    method public int getDetectionMethod();
-    method @NonNull public android.net.LinkProperties getLinkProperties();
-    method @NonNull public android.net.Network getNetwork();
-    method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities();
-    method public long getReportTimestamp();
-    method @NonNull public android.os.PersistableBundle getStallDetails();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.ConnectivityDiagnosticsManager.DataStallReport> CREATOR;
-    field public static final int DETECTION_METHOD_DNS_EVENTS = 1; // 0x1
-    field public static final int DETECTION_METHOD_TCP_METRICS = 2; // 0x2
-    field public static final String KEY_DNS_CONSECUTIVE_TIMEOUTS = "dnsConsecutiveTimeouts";
-    field public static final String KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS = "tcpMetricsCollectionPeriodMillis";
-    field public static final String KEY_TCP_PACKET_FAIL_RATE = "tcpPacketFailRate";
-  }
-
-  public class ConnectivityManager {
-    method public void addDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
-    method public boolean bindProcessToNetwork(@Nullable android.net.Network);
-    method @NonNull public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull android.net.IpSecManager.UdpEncapsulationSocket, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
-    method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network getActiveNetwork();
-    method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getActiveNetworkInfo();
-    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo[] getAllNetworkInfo();
-    method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network[] getAllNetworks();
-    method @Deprecated public boolean getBackgroundDataSetting();
-    method @Nullable public android.net.Network getBoundNetworkForProcess();
-    method public int getConnectionOwnerUid(int, @NonNull java.net.InetSocketAddress, @NonNull java.net.InetSocketAddress);
-    method @Nullable public android.net.ProxyInfo getDefaultProxy();
-    method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.LinkProperties getLinkProperties(@Nullable android.net.Network);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public int getMultipathPreference(@Nullable android.net.Network);
-    method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkCapabilities getNetworkCapabilities(@Nullable android.net.Network);
-    method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getNetworkInfo(int);
-    method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getNetworkInfo(@Nullable android.net.Network);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public int getNetworkPreference();
-    method @Nullable public byte[] getNetworkWatchlistConfigHash();
-    method @Deprecated @Nullable public static android.net.Network getProcessDefaultNetwork();
-    method public int getRestrictBackgroundStatus();
-    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public boolean isActiveNetworkMetered();
-    method public boolean isDefaultNetworkActive();
-    method @Deprecated public static boolean isNetworkTypeValid(int);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.app.PendingIntent);
-    method public void releaseNetworkRequest(@NonNull android.app.PendingIntent);
-    method public void removeDefaultNetworkActiveListener(@NonNull android.net.ConnectivityManager.OnNetworkActiveListener);
-    method @Deprecated public void reportBadNetwork(@Nullable android.net.Network);
-    method public void reportNetworkConnectivity(@Nullable android.net.Network, boolean);
-    method public boolean requestBandwidthUpdate(@NonNull android.net.Network);
-    method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback);
-    method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
-    method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, int);
-    method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler, int);
-    method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.app.PendingIntent);
-    method @Deprecated public void setNetworkPreference(int);
-    method @Deprecated public static boolean setProcessDefaultNetwork(@Nullable android.net.Network);
-    method public void unregisterNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback);
-    method public void unregisterNetworkCallback(@NonNull android.app.PendingIntent);
-    field @Deprecated public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
-    field public static final String ACTION_CAPTIVE_PORTAL_SIGN_IN = "android.net.conn.CAPTIVE_PORTAL";
-    field public static final String ACTION_RESTRICT_BACKGROUND_CHANGED = "android.net.conn.RESTRICT_BACKGROUND_CHANGED";
-    field @Deprecated public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
-    field @Deprecated public static final int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
-    field public static final String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL";
-    field public static final String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL";
-    field @Deprecated public static final String EXTRA_EXTRA_INFO = "extraInfo";
-    field @Deprecated public static final String EXTRA_IS_FAILOVER = "isFailover";
-    field public static final String EXTRA_NETWORK = "android.net.extra.NETWORK";
-    field @Deprecated public static final String EXTRA_NETWORK_INFO = "networkInfo";
-    field public static final String EXTRA_NETWORK_REQUEST = "android.net.extra.NETWORK_REQUEST";
-    field @Deprecated public static final String EXTRA_NETWORK_TYPE = "networkType";
-    field public static final String EXTRA_NO_CONNECTIVITY = "noConnectivity";
-    field @Deprecated public static final String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
-    field public static final String EXTRA_REASON = "reason";
-    field public static final int MULTIPATH_PREFERENCE_HANDOVER = 1; // 0x1
-    field public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 4; // 0x4
-    field public static final int MULTIPATH_PREFERENCE_RELIABILITY = 2; // 0x2
-    field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
-    field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
-    field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
-    field @Deprecated public static final int TYPE_BLUETOOTH = 7; // 0x7
-    field @Deprecated public static final int TYPE_DUMMY = 8; // 0x8
-    field @Deprecated public static final int TYPE_ETHERNET = 9; // 0x9
-    field @Deprecated public static final int TYPE_MOBILE = 0; // 0x0
-    field @Deprecated public static final int TYPE_MOBILE_DUN = 4; // 0x4
-    field @Deprecated public static final int TYPE_MOBILE_HIPRI = 5; // 0x5
-    field @Deprecated public static final int TYPE_MOBILE_MMS = 2; // 0x2
-    field @Deprecated public static final int TYPE_MOBILE_SUPL = 3; // 0x3
-    field @Deprecated public static final int TYPE_VPN = 17; // 0x11
-    field @Deprecated public static final int TYPE_WIFI = 1; // 0x1
-    field @Deprecated public static final int TYPE_WIMAX = 6; // 0x6
-  }
-
-  public static class ConnectivityManager.NetworkCallback {
-    ctor public ConnectivityManager.NetworkCallback();
-    method public void onAvailable(@NonNull android.net.Network);
-    method public void onBlockedStatusChanged(@NonNull android.net.Network, boolean);
-    method public void onCapabilitiesChanged(@NonNull android.net.Network, @NonNull android.net.NetworkCapabilities);
-    method public void onLinkPropertiesChanged(@NonNull android.net.Network, @NonNull android.net.LinkProperties);
-    method public void onLosing(@NonNull android.net.Network, int);
-    method public void onLost(@NonNull android.net.Network);
-    method public void onUnavailable();
-  }
-
-  public static interface ConnectivityManager.OnNetworkActiveListener {
-    method public void onNetworkActive();
-  }
-
   public class Credentials {
     ctor public Credentials(int, int, int);
     method public int getGid();
@@ -25970,46 +25862,6 @@
     method public int getUid();
   }
 
-  public class DhcpInfo implements android.os.Parcelable {
-    ctor public DhcpInfo();
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.DhcpInfo> CREATOR;
-    field public int dns1;
-    field public int dns2;
-    field public int gateway;
-    field public int ipAddress;
-    field public int leaseDuration;
-    field public int netmask;
-    field public int serverAddress;
-  }
-
-  public final class DnsResolver {
-    method @NonNull public static android.net.DnsResolver getInstance();
-    method public void query(@Nullable android.net.Network, @NonNull String, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super java.util.List<java.net.InetAddress>>);
-    method public void query(@Nullable android.net.Network, @NonNull String, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super java.util.List<java.net.InetAddress>>);
-    method public void rawQuery(@Nullable android.net.Network, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super byte[]>);
-    method public void rawQuery(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super byte[]>);
-    field public static final int CLASS_IN = 1; // 0x1
-    field public static final int ERROR_PARSE = 0; // 0x0
-    field public static final int ERROR_SYSTEM = 1; // 0x1
-    field public static final int FLAG_EMPTY = 0; // 0x0
-    field public static final int FLAG_NO_CACHE_LOOKUP = 4; // 0x4
-    field public static final int FLAG_NO_CACHE_STORE = 2; // 0x2
-    field public static final int FLAG_NO_RETRY = 1; // 0x1
-    field public static final int TYPE_A = 1; // 0x1
-    field public static final int TYPE_AAAA = 28; // 0x1c
-  }
-
-  public static interface DnsResolver.Callback<T> {
-    method public void onAnswer(@NonNull T, int);
-    method public void onError(@NonNull android.net.DnsResolver.DnsException);
-  }
-
-  public static class DnsResolver.DnsException extends java.lang.Exception {
-    field public final int code;
-  }
-
   public final class Ikev2VpnProfile extends android.net.PlatformVpnProfile {
     method @NonNull public java.util.List<java.lang.String> getAllowedAlgorithms();
     method public int getMaxMtu();
@@ -26039,21 +25891,6 @@
     method @NonNull public android.net.Ikev2VpnProfile.Builder setProxy(@Nullable android.net.ProxyInfo);
   }
 
-  public class InetAddresses {
-    method public static boolean isNumericAddress(@NonNull String);
-    method @NonNull public static java.net.InetAddress parseNumericAddress(@NonNull String);
-  }
-
-  public final class IpPrefix implements android.os.Parcelable {
-    method public boolean contains(@NonNull java.net.InetAddress);
-    method public int describeContents();
-    method @NonNull public java.net.InetAddress getAddress();
-    method @IntRange(from=0, to=128) public int getPrefixLength();
-    method @NonNull public byte[] getRawAddress();
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
-  }
-
   public final class IpSecAlgorithm implements android.os.Parcelable {
     ctor public IpSecAlgorithm(@NonNull String, @NonNull byte[]);
     ctor public IpSecAlgorithm(@NonNull String, @NonNull byte[], int);
@@ -26063,6 +25900,7 @@
     method @NonNull public static java.util.Set<java.lang.String> getSupportedAlgorithms();
     method public int getTruncationLengthBits();
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final String AUTH_AES_CMAC = "cmac(aes)";
     field public static final String AUTH_AES_XCBC = "xcbc(aes)";
     field public static final String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))";
     field public static final String AUTH_CRYPT_CHACHA20_POLY1305 = "rfc7539esp(chacha20,poly1305)";
@@ -26122,45 +25960,6 @@
     method @NonNull public android.net.IpSecTransform.Builder setIpv4Encapsulation(@NonNull android.net.IpSecManager.UdpEncapsulationSocket, int);
   }
 
-  public class LinkAddress implements android.os.Parcelable {
-    method public int describeContents();
-    method public java.net.InetAddress getAddress();
-    method public int getFlags();
-    method @IntRange(from=0, to=128) public int getPrefixLength();
-    method public int getScope();
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.LinkAddress> CREATOR;
-  }
-
-  public final class LinkProperties implements android.os.Parcelable {
-    ctor public LinkProperties();
-    method public boolean addRoute(@NonNull android.net.RouteInfo);
-    method public void clear();
-    method public int describeContents();
-    method @Nullable public java.net.Inet4Address getDhcpServerAddress();
-    method @NonNull public java.util.List<java.net.InetAddress> getDnsServers();
-    method @Nullable public String getDomains();
-    method @Nullable public android.net.ProxyInfo getHttpProxy();
-    method @Nullable public String getInterfaceName();
-    method @NonNull public java.util.List<android.net.LinkAddress> getLinkAddresses();
-    method public int getMtu();
-    method @Nullable public android.net.IpPrefix getNat64Prefix();
-    method @Nullable public String getPrivateDnsServerName();
-    method @NonNull public java.util.List<android.net.RouteInfo> getRoutes();
-    method public boolean isPrivateDnsActive();
-    method public boolean isWakeOnLanSupported();
-    method public void setDhcpServerAddress(@Nullable java.net.Inet4Address);
-    method public void setDnsServers(@NonNull java.util.Collection<java.net.InetAddress>);
-    method public void setDomains(@Nullable String);
-    method public void setHttpProxy(@Nullable android.net.ProxyInfo);
-    method public void setInterfaceName(@Nullable String);
-    method public void setLinkAddresses(@NonNull java.util.Collection<android.net.LinkAddress>);
-    method public void setMtu(int);
-    method public void setNat64Prefix(@Nullable android.net.IpPrefix);
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.LinkProperties> CREATOR;
-  }
-
   public class LocalServerSocket implements java.io.Closeable {
     ctor public LocalServerSocket(String) throws java.io.IOException;
     ctor public LocalServerSocket(java.io.FileDescriptor) throws java.io.IOException;
@@ -26216,24 +26015,6 @@
     enum_constant public static final android.net.LocalSocketAddress.Namespace RESERVED;
   }
 
-  public final class MacAddress implements android.os.Parcelable {
-    method public int describeContents();
-    method @NonNull public static android.net.MacAddress fromBytes(@NonNull byte[]);
-    method @NonNull public static android.net.MacAddress fromString(@NonNull String);
-    method public int getAddressType();
-    method @Nullable public java.net.Inet6Address getLinkLocalIpv6FromEui48Mac();
-    method public boolean isLocallyAssigned();
-    method public boolean matches(@NonNull android.net.MacAddress, @NonNull android.net.MacAddress);
-    method @NonNull public byte[] toByteArray();
-    method @NonNull public String toOuiString();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.net.MacAddress BROADCAST_ADDRESS;
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.MacAddress> CREATOR;
-    field public static final int TYPE_BROADCAST = 3; // 0x3
-    field public static final int TYPE_MULTICAST = 2; // 0x2
-    field public static final int TYPE_UNICAST = 1; // 0x1
-  }
-
   public class MailTo {
     method public String getBody();
     method public String getCc();
@@ -26245,139 +26026,6 @@
     field public static final String MAILTO_SCHEME = "mailto:";
   }
 
-  public class Network implements android.os.Parcelable {
-    method public void bindSocket(java.net.DatagramSocket) throws java.io.IOException;
-    method public void bindSocket(java.net.Socket) throws java.io.IOException;
-    method public void bindSocket(java.io.FileDescriptor) throws java.io.IOException;
-    method public int describeContents();
-    method public static android.net.Network fromNetworkHandle(long);
-    method public java.net.InetAddress[] getAllByName(String) throws java.net.UnknownHostException;
-    method public java.net.InetAddress getByName(String) throws java.net.UnknownHostException;
-    method public long getNetworkHandle();
-    method public javax.net.SocketFactory getSocketFactory();
-    method public java.net.URLConnection openConnection(java.net.URL) throws java.io.IOException;
-    method public java.net.URLConnection openConnection(java.net.URL, java.net.Proxy) throws java.io.IOException;
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.Network> CREATOR;
-  }
-
-  public final class NetworkCapabilities implements android.os.Parcelable {
-    ctor public NetworkCapabilities();
-    ctor public NetworkCapabilities(android.net.NetworkCapabilities);
-    method public int describeContents();
-    method public int getLinkDownstreamBandwidthKbps();
-    method public int getLinkUpstreamBandwidthKbps();
-    method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
-    method public int getOwnerUid();
-    method public int getSignalStrength();
-    method @Nullable public android.net.TransportInfo getTransportInfo();
-    method public boolean hasCapability(int);
-    method public boolean hasTransport(int);
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkCapabilities> CREATOR;
-    field public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17; // 0x11
-    field public static final int NET_CAPABILITY_CBS = 5; // 0x5
-    field public static final int NET_CAPABILITY_DUN = 2; // 0x2
-    field public static final int NET_CAPABILITY_EIMS = 10; // 0xa
-    field public static final int NET_CAPABILITY_ENTERPRISE = 29; // 0x1d
-    field public static final int NET_CAPABILITY_FOREGROUND = 19; // 0x13
-    field public static final int NET_CAPABILITY_FOTA = 3; // 0x3
-    field public static final int NET_CAPABILITY_IA = 7; // 0x7
-    field public static final int NET_CAPABILITY_IMS = 4; // 0x4
-    field public static final int NET_CAPABILITY_INTERNET = 12; // 0xc
-    field public static final int NET_CAPABILITY_MCX = 23; // 0x17
-    field public static final int NET_CAPABILITY_MMS = 0; // 0x0
-    field public static final int NET_CAPABILITY_NOT_CONGESTED = 20; // 0x14
-    field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
-    field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
-    field public static final int NET_CAPABILITY_NOT_ROAMING = 18; // 0x12
-    field public static final int NET_CAPABILITY_NOT_SUSPENDED = 21; // 0x15
-    field public static final int NET_CAPABILITY_NOT_VPN = 15; // 0xf
-    field public static final int NET_CAPABILITY_RCS = 8; // 0x8
-    field public static final int NET_CAPABILITY_SUPL = 1; // 0x1
-    field public static final int NET_CAPABILITY_TEMPORARILY_NOT_METERED = 25; // 0x19
-    field public static final int NET_CAPABILITY_TRUSTED = 14; // 0xe
-    field public static final int NET_CAPABILITY_VALIDATED = 16; // 0x10
-    field public static final int NET_CAPABILITY_WIFI_P2P = 6; // 0x6
-    field public static final int NET_CAPABILITY_XCAP = 9; // 0x9
-    field public static final int SIGNAL_STRENGTH_UNSPECIFIED = -2147483648; // 0x80000000
-    field public static final int TRANSPORT_BLUETOOTH = 2; // 0x2
-    field public static final int TRANSPORT_CELLULAR = 0; // 0x0
-    field public static final int TRANSPORT_ETHERNET = 3; // 0x3
-    field public static final int TRANSPORT_LOWPAN = 6; // 0x6
-    field public static final int TRANSPORT_VPN = 4; // 0x4
-    field public static final int TRANSPORT_WIFI = 1; // 0x1
-    field public static final int TRANSPORT_WIFI_AWARE = 5; // 0x5
-  }
-
-  @Deprecated public class NetworkInfo implements android.os.Parcelable {
-    ctor @Deprecated public NetworkInfo(int, int, @Nullable String, @Nullable String);
-    method @Deprecated public int describeContents();
-    method @Deprecated @NonNull public android.net.NetworkInfo.DetailedState getDetailedState();
-    method @Deprecated public String getExtraInfo();
-    method @Deprecated public String getReason();
-    method @Deprecated public android.net.NetworkInfo.State getState();
-    method @Deprecated public int getSubtype();
-    method @Deprecated public String getSubtypeName();
-    method @Deprecated public int getType();
-    method @Deprecated public String getTypeName();
-    method @Deprecated public boolean isAvailable();
-    method @Deprecated public boolean isConnected();
-    method @Deprecated public boolean isConnectedOrConnecting();
-    method @Deprecated public boolean isFailover();
-    method @Deprecated public boolean isRoaming();
-    method @Deprecated public void setDetailedState(@NonNull android.net.NetworkInfo.DetailedState, @Nullable String, @Nullable String);
-    method @Deprecated public void writeToParcel(android.os.Parcel, int);
-    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR;
-  }
-
-  @Deprecated public enum NetworkInfo.DetailedState {
-    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState AUTHENTICATING;
-    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState BLOCKED;
-    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CAPTIVE_PORTAL_CHECK;
-    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CONNECTED;
-    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CONNECTING;
-    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState DISCONNECTED;
-    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState DISCONNECTING;
-    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState FAILED;
-    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState IDLE;
-    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState OBTAINING_IPADDR;
-    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState SCANNING;
-    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState SUSPENDED;
-    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState VERIFYING_POOR_LINK;
-  }
-
-  @Deprecated public enum NetworkInfo.State {
-    enum_constant @Deprecated public static final android.net.NetworkInfo.State CONNECTED;
-    enum_constant @Deprecated public static final android.net.NetworkInfo.State CONNECTING;
-    enum_constant @Deprecated public static final android.net.NetworkInfo.State DISCONNECTED;
-    enum_constant @Deprecated public static final android.net.NetworkInfo.State DISCONNECTING;
-    enum_constant @Deprecated public static final android.net.NetworkInfo.State SUSPENDED;
-    enum_constant @Deprecated public static final android.net.NetworkInfo.State UNKNOWN;
-  }
-
-  public class NetworkRequest implements android.os.Parcelable {
-    method public boolean canBeSatisfiedBy(@Nullable android.net.NetworkCapabilities);
-    method public int describeContents();
-    method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
-    method public boolean hasCapability(int);
-    method public boolean hasTransport(int);
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkRequest> CREATOR;
-  }
-
-  public static class NetworkRequest.Builder {
-    ctor public NetworkRequest.Builder();
-    method public android.net.NetworkRequest.Builder addCapability(int);
-    method public android.net.NetworkRequest.Builder addTransportType(int);
-    method public android.net.NetworkRequest build();
-    method @NonNull public android.net.NetworkRequest.Builder clearCapabilities();
-    method public android.net.NetworkRequest.Builder removeCapability(int);
-    method public android.net.NetworkRequest.Builder removeTransportType(int);
-    method @Deprecated public android.net.NetworkRequest.Builder setNetworkSpecifier(String);
-    method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
-  }
-
   public abstract class NetworkSpecifier {
     ctor public NetworkSpecifier();
   }
@@ -26404,34 +26052,6 @@
     field public static final String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
   }
 
-  public class ProxyInfo implements android.os.Parcelable {
-    ctor public ProxyInfo(@Nullable android.net.ProxyInfo);
-    method public static android.net.ProxyInfo buildDirectProxy(String, int);
-    method public static android.net.ProxyInfo buildDirectProxy(String, int, java.util.List<java.lang.String>);
-    method public static android.net.ProxyInfo buildPacProxy(android.net.Uri);
-    method @NonNull public static android.net.ProxyInfo buildPacProxy(@NonNull android.net.Uri, int);
-    method public int describeContents();
-    method public String[] getExclusionList();
-    method public String getHost();
-    method public android.net.Uri getPacFileUrl();
-    method public int getPort();
-    method public boolean isValid();
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.ProxyInfo> CREATOR;
-  }
-
-  public final class RouteInfo implements android.os.Parcelable {
-    method public int describeContents();
-    method @NonNull public android.net.IpPrefix getDestination();
-    method @Nullable public java.net.InetAddress getGateway();
-    method @Nullable public String getInterface();
-    method public boolean hasGateway();
-    method public boolean isDefaultRoute();
-    method public boolean matches(java.net.InetAddress);
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.RouteInfo> CREATOR;
-  }
-
   @Deprecated public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
     ctor @Deprecated public SSLCertificateSocketFactory(int);
     method @Deprecated public java.net.Socket createSocket(java.net.Socket, String, int, boolean) throws java.io.IOException;
@@ -26457,30 +26077,6 @@
     ctor public SSLSessionCache(android.content.Context);
   }
 
-  public abstract class SocketKeepalive implements java.lang.AutoCloseable {
-    method public final void close();
-    method public final void start(@IntRange(from=0xa, to=0xe10) int);
-    method public final void stop();
-    field public static final int ERROR_HARDWARE_ERROR = -31; // 0xffffffe1
-    field public static final int ERROR_INSUFFICIENT_RESOURCES = -32; // 0xffffffe0
-    field public static final int ERROR_INVALID_INTERVAL = -24; // 0xffffffe8
-    field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb
-    field public static final int ERROR_INVALID_LENGTH = -23; // 0xffffffe9
-    field public static final int ERROR_INVALID_NETWORK = -20; // 0xffffffec
-    field public static final int ERROR_INVALID_PORT = -22; // 0xffffffea
-    field public static final int ERROR_INVALID_SOCKET = -25; // 0xffffffe7
-    field public static final int ERROR_SOCKET_NOT_IDLE = -26; // 0xffffffe6
-    field public static final int ERROR_UNSUPPORTED = -30; // 0xffffffe2
-  }
-
-  public static class SocketKeepalive.Callback {
-    ctor public SocketKeepalive.Callback();
-    method public void onDataReceived();
-    method public void onError(int);
-    method public void onStarted();
-    method public void onStopped();
-  }
-
   public final class TelephonyNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
     method public int describeContents();
     method public int getSubscriptionId();
@@ -26538,9 +26134,6 @@
     field public static final int UNSUPPORTED = -1; // 0xffffffff
   }
 
-  public interface TransportInfo {
-  }
-
   public abstract class Uri implements java.lang.Comparable<android.net.Uri> android.os.Parcelable {
     method public abstract android.net.Uri.Builder buildUpon();
     method public int compareTo(android.net.Uri);
@@ -30838,19 +30431,10 @@
   public abstract class CombinedVibrationEffect implements android.os.Parcelable {
     method @NonNull public static android.os.CombinedVibrationEffect createSynced(@NonNull android.os.VibrationEffect);
     method public int describeContents();
-    method @NonNull public static android.os.CombinedVibrationEffect.SequentialCombination startSequential();
     method @NonNull public static android.os.CombinedVibrationEffect.SyncedCombination startSynced();
     field @NonNull public static final android.os.Parcelable.Creator<android.os.CombinedVibrationEffect> CREATOR;
   }
 
-  public static final class CombinedVibrationEffect.SequentialCombination {
-    method @NonNull public android.os.CombinedVibrationEffect.SequentialCombination addNext(int, @NonNull android.os.VibrationEffect);
-    method @NonNull public android.os.CombinedVibrationEffect.SequentialCombination addNext(int, @NonNull android.os.VibrationEffect, int);
-    method @NonNull public android.os.CombinedVibrationEffect.SequentialCombination addNext(@NonNull android.os.CombinedVibrationEffect);
-    method @NonNull public android.os.CombinedVibrationEffect.SequentialCombination addNext(@NonNull android.os.CombinedVibrationEffect, int);
-    method @NonNull public android.os.CombinedVibrationEffect combine();
-  }
-
   public static final class CombinedVibrationEffect.SyncedCombination {
     method @NonNull public android.os.CombinedVibrationEffect.SyncedCombination addVibrator(int, @NonNull android.os.VibrationEffect);
     method @NonNull public android.os.CombinedVibrationEffect combine();
@@ -31913,10 +31497,10 @@
     method public static android.content.Intent createUserCreationIntent(@Nullable String, @Nullable String, @Nullable String, @Nullable android.os.PersistableBundle);
     method @WorkerThread public android.os.Bundle getApplicationRestrictions(String);
     method public long getSerialNumberForUser(android.os.UserHandle);
-    method @RequiresPermission("android.permission.MANAGE_USERS") public int getUserCount();
+    method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.CREATE_USERS"}) public int getUserCount();
     method public long getUserCreationTime(android.os.UserHandle);
     method public android.os.UserHandle getUserForSerialNumber(long);
-    method @NonNull @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}, conditional=true) public String getUserName();
+    method @NonNull @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED, "android.permission.CREATE_USERS"}, conditional=true) public String getUserName();
     method public java.util.List<android.os.UserHandle> getUserProfiles();
     method public android.os.Bundle getUserRestrictions();
     method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.INTERACT_ACROSS_USERS"}, conditional=true) public android.os.Bundle getUserRestrictions(android.os.UserHandle);
@@ -32275,6 +31859,7 @@
     method @WorkerThread public long getAllocatableBytes(@NonNull java.util.UUID) throws java.io.IOException;
     method @WorkerThread public long getCacheQuotaBytes(@NonNull java.util.UUID) throws java.io.IOException;
     method @WorkerThread public long getCacheSizeBytes(@NonNull java.util.UUID) throws java.io.IOException;
+    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_EXTERNAL_STORAGE) public android.app.PendingIntent getManageSpaceActivityIntent(@NonNull String, int);
     method public String getMountedObbPath(String);
     method @NonNull public android.os.storage.StorageVolume getPrimaryStorageVolume();
     method @NonNull public java.util.List<android.os.storage.StorageVolume> getRecentStorageVolumes();
@@ -35110,6 +34695,7 @@
     field public static final String ACTION_QUICK_ACCESS_WALLET_SETTINGS = "android.settings.QUICK_ACCESS_WALLET_SETTINGS";
     field public static final String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS";
     field public static final String ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
+    field public static final String ACTION_REQUEST_SCHEDULE_EXACT_ALARM = "android.settings.REQUEST_SCHEDULE_EXACT_ALARM";
     field public static final String ACTION_REQUEST_SET_AUTOFILL_SERVICE = "android.settings.REQUEST_SET_AUTOFILL_SERVICE";
     field public static final String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
     field public static final String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
@@ -37154,8 +36740,10 @@
     method @NonNull public static android.content.Intent createInstallIntent();
     method @NonNull public static android.content.Intent createManageCredentialsIntent(@NonNull android.security.AppUriAuthenticationPolicy);
     method @Nullable @WorkerThread public static java.security.cert.X509Certificate[] getCertificateChain(@NonNull android.content.Context, @NonNull String) throws java.lang.InterruptedException, android.security.KeyChainException;
+    method @NonNull public static android.security.AppUriAuthenticationPolicy getCredentialManagementAppPolicy(@NonNull android.content.Context) throws java.lang.SecurityException;
     method @Nullable @WorkerThread public static java.security.PrivateKey getPrivateKey(@NonNull android.content.Context, @NonNull String) throws java.lang.InterruptedException, android.security.KeyChainException;
     method @Deprecated public static boolean isBoundKeyAlgorithm(@NonNull String);
+    method public static boolean isCredentialManagementApp(@NonNull android.content.Context);
     method public static boolean isKeyAlgorithmSupported(@NonNull String);
     field public static final String ACTION_KEYCHAIN_CHANGED = "android.security.action.KEYCHAIN_CHANGED";
     field public static final String ACTION_KEY_ACCESS_CHANGED = "android.security.action.KEY_ACCESS_CHANGED";
@@ -38525,6 +38113,7 @@
     field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2
     field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
     field public static final String META_DATA_DEFAULT_FILTER_TYPES = "android.service.notification.default_filter_types";
+    field public static final String META_DATA_DISABLED_FILTER_TYPES = "android.service.notification.disabled_filter_types";
     field public static final int NOTIFICATION_CHANNEL_OR_GROUP_ADDED = 1; // 0x1
     field public static final int NOTIFICATION_CHANNEL_OR_GROUP_DELETED = 3; // 0x3
     field public static final int NOTIFICATION_CHANNEL_OR_GROUP_UPDATED = 2; // 0x2
@@ -39396,6 +38985,10 @@
     method public void unhold();
     method public void unregisterCallback(android.telecom.Call.Callback);
     field @Deprecated public static final String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts";
+    field public static final String EVENT_CLEAR_DIAGNOSTIC_MESSAGE = "android.telecom.event.CLEAR_DIAGNOSTIC_MESSAGE";
+    field public static final String EVENT_DISPLAY_DIAGNOSTIC_MESSAGE = "android.telecom.event.DISPLAY_DIAGNOSTIC_MESSAGE";
+    field public static final String EXTRA_DIAGNOSTIC_MESSAGE = "android.telecom.extra.DIAGNOSTIC_MESSAGE";
+    field public static final String EXTRA_DIAGNOSTIC_MESSAGE_ID = "android.telecom.extra.DIAGNOSTIC_MESSAGE_ID";
     field public static final String EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS = "android.telecom.extra.LAST_EMERGENCY_CALLBACK_TIME_MILLIS";
     field public static final String EXTRA_SILENT_RINGING_REQUESTED = "android.telecom.extra.SILENT_RINGING_REQUESTED";
     field public static final String EXTRA_SUGGESTED_PHONE_ACCOUNTS = "android.telecom.extra.SUGGESTED_PHONE_ACCOUNTS";
@@ -40235,7 +39828,7 @@
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailNumber(android.telecom.PhoneAccountHandle);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handleMmi(String);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handleMmi(String, android.telecom.PhoneAccountHandle);
-    method public boolean hasCompanionInCallServiceAccess();
+    method public boolean hasManageOngoingCallsPermission();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isInCall();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isInManagedCall();
     method public boolean isIncomingCallPermitted(android.telecom.PhoneAccountHandle);
@@ -40862,6 +40455,7 @@
   }
 
   public static final class CarrierConfigManager.Apn {
+    field @Deprecated public static final String KEY_PREFIX = "apn.";
     field public static final String KEY_SETTINGS_DEFAULT_PROTOCOL_STRING = "apn.settings_default_protocol_string";
     field public static final String KEY_SETTINGS_DEFAULT_ROAMING_PROTOCOL_STRING = "apn.settings_default_roaming_protocol_string";
     field public static final String PROTOCOL_IPV4 = "IP";
@@ -40886,7 +40480,7 @@
   }
 
   public static final class CarrierConfigManager.ImsServiceEntitlement {
-    field public static final String KEY_AES_URL_STRING = "imsserviceentitlement.aes_url_string";
+    field public static final String KEY_ENTITLEMENT_SERVER_URL_STRING = "imsserviceentitlement.entitlement_server_url_string";
     field public static final String KEY_PREFIX = "imsserviceentitlement.";
   }
 
@@ -41759,7 +41353,6 @@
     method @NonNull public java.util.List<java.lang.Integer> getAvailableServices();
     method @Nullable public android.telephony.CellIdentity getCellIdentity();
     method public int getDomain();
-    method public int getNrState();
     method @Nullable public String getRegisteredPlmn();
     method public int getTransportType();
     method public boolean isRegistered();
@@ -42114,7 +41707,6 @@
 
   public final class SignalStrengthUpdateRequest implements android.os.Parcelable {
     method public int describeContents();
-    method @NonNull public android.os.IBinder getLiveToken();
     method @NonNull public java.util.Collection<android.telephony.SignalThresholdInfo> getSignalThresholdInfos();
     method public boolean isReportingRequestedWhileIdle();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -42647,7 +42239,6 @@
     field public static final int AUTHTYPE_EAP_SIM = 128; // 0x80
     field public static final int CALL_COMPOSER_STATUS_OFF = 0; // 0x0
     field public static final int CALL_COMPOSER_STATUS_ON = 1; // 0x1
-    field public static final int CALL_COMPOSER_STATUS_ON_NO_PICTURES = 2; // 0x2
     field public static final int CALL_STATE_IDLE = 0; // 0x0
     field public static final int CALL_STATE_OFFHOOK = 2; // 0x2
     field public static final int CALL_STATE_RINGING = 1; // 0x1
@@ -46296,7 +45887,7 @@
     method public void clear();
     method public android.util.SparseArray<E> clone();
     method public boolean contains(int);
-    method public boolean contentEquals(@Nullable android.util.SparseArray<E>);
+    method public boolean contentEquals(@Nullable android.util.SparseArray<?>);
     method public int contentHashCode();
     method public void delete(int);
     method public E get(int);
@@ -46692,6 +46283,7 @@
     method public long getAppVsyncOffsetNanos();
     method public void getCurrentSizeRange(android.graphics.Point, android.graphics.Point);
     method @Nullable public android.view.DisplayCutout getCutout();
+    method @Nullable public android.hardware.display.DeviceProductInfo getDeviceProductInfo();
     method public int getDisplayId();
     method public int getFlags();
     method public android.view.Display.HdrCapabilities getHdrCapabilities();
@@ -48015,16 +47607,47 @@
     method public void onScaleEnd(android.view.ScaleGestureDetector);
   }
 
+  @UiThread public interface ScrollCaptureCallback {
+    method public void onScrollCaptureEnd(@NonNull Runnable);
+    method public void onScrollCaptureImageRequest(@NonNull android.view.ScrollCaptureSession, @NonNull android.os.CancellationSignal, @NonNull android.graphics.Rect, @NonNull java.util.function.Consumer<android.graphics.Rect>);
+    method public void onScrollCaptureSearch(@NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<android.graphics.Rect>);
+    method public void onScrollCaptureStart(@NonNull android.view.ScrollCaptureSession, @NonNull android.os.CancellationSignal, @NonNull Runnable);
+  }
+
+  public class ScrollCaptureSession {
+    ctor public ScrollCaptureSession(@NonNull android.view.Surface, @NonNull android.graphics.Rect, @NonNull android.graphics.Point);
+    method @NonNull public android.graphics.Point getPositionInWindow();
+    method @NonNull public android.graphics.Rect getScrollBounds();
+    method @NonNull public android.view.Surface getSurface();
+  }
+
+  public final class ScrollCaptureTarget {
+    ctor public ScrollCaptureTarget(@NonNull android.view.View, @NonNull android.graphics.Rect, @NonNull android.graphics.Point, @NonNull android.view.ScrollCaptureCallback);
+    method @NonNull public android.view.ScrollCaptureCallback getCallback();
+    method @NonNull public android.view.View getContainingView();
+    method public int getHint();
+    method @NonNull public android.graphics.Rect getLocalVisibleRect();
+    method @NonNull public android.graphics.Point getPositionInWindow();
+    method @Nullable public android.graphics.Rect getScrollBounds();
+    method public void setScrollBounds(@Nullable android.graphics.Rect);
+    method @UiThread public void updatePositionInWindow();
+  }
+
   public class SearchEvent {
     ctor public SearchEvent(android.view.InputDevice);
     method public android.view.InputDevice getInputDevice();
   }
 
   public class SoundEffectConstants {
+    method public static int getConstantForFocusDirection(int, boolean);
     method public static int getContantForFocusDirection(int);
     field public static final int CLICK = 0; // 0x0
     field public static final int NAVIGATION_DOWN = 4; // 0x4
     field public static final int NAVIGATION_LEFT = 1; // 0x1
+    field public static final int NAVIGATION_REPEAT_DOWN = 8; // 0x8
+    field public static final int NAVIGATION_REPEAT_LEFT = 5; // 0x5
+    field public static final int NAVIGATION_REPEAT_RIGHT = 7; // 0x7
+    field public static final int NAVIGATION_REPEAT_UP = 6; // 0x6
     field public static final int NAVIGATION_RIGHT = 3; // 0x3
     field public static final int NAVIGATION_UP = 2; // 0x2
   }
@@ -48336,6 +47959,7 @@
     method public void dispatchProvideStructure(android.view.ViewStructure);
     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>);
     method protected void dispatchSetActivated(boolean);
     method protected void dispatchSetPressed(boolean);
     method protected void dispatchSetSelected(boolean);
@@ -48495,6 +48119,7 @@
     method public int getScrollBarFadeDuration();
     method public int getScrollBarSize();
     method public int getScrollBarStyle();
+    method public int getScrollCaptureHint();
     method public int getScrollIndicators();
     method public final int getScrollX();
     method public final int getScrollY();
@@ -48663,6 +48288,7 @@
     method public void onRtlPropertiesChanged(int);
     method @CallSuper @Nullable protected android.os.Parcelable onSaveInstanceState();
     method public void onScreenStateChanged(int);
+    method public void onScrollCaptureSearch(@NonNull android.graphics.Rect, @NonNull android.graphics.Point, @NonNull java.util.function.Consumer<android.view.ScrollCaptureTarget>);
     method protected void onScrollChanged(int, int, int, int);
     method protected boolean onSetAlpha(int);
     method protected void onSizeChanged(int, int, int, int);
@@ -48845,6 +48471,8 @@
     method public void setScrollBarFadeDuration(int);
     method public void setScrollBarSize(int);
     method public void setScrollBarStyle(int);
+    method public final void setScrollCaptureCallback(@Nullable android.view.ScrollCaptureCallback);
+    method public void setScrollCaptureHint(int);
     method public void setScrollContainer(boolean);
     method public void setScrollIndicators(int);
     method public void setScrollIndicators(int, int);
@@ -49023,6 +48651,10 @@
     field public static final int SCROLL_AXIS_HORIZONTAL = 1; // 0x1
     field public static final int SCROLL_AXIS_NONE = 0; // 0x0
     field public static final int SCROLL_AXIS_VERTICAL = 2; // 0x2
+    field public static final int SCROLL_CAPTURE_HINT_AUTO = 0; // 0x0
+    field public static final int SCROLL_CAPTURE_HINT_EXCLUDE = 1; // 0x1
+    field public static final int SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS = 4; // 0x4
+    field public static final int SCROLL_CAPTURE_HINT_INCLUDE = 2; // 0x2
     field public static final int SCROLL_INDICATOR_BOTTOM = 2; // 0x2
     field public static final int SCROLL_INDICATOR_END = 32; // 0x20
     field public static final int SCROLL_INDICATOR_LEFT = 4; // 0x4
@@ -49807,6 +49439,7 @@
     method public abstract boolean performContextMenuIdentifierAction(int, int);
     method public abstract boolean performPanelIdentifierAction(int, int, int);
     method public abstract boolean performPanelShortcut(int, int, android.view.KeyEvent, int);
+    method public void registerScrollCaptureCallback(@NonNull android.view.ScrollCaptureCallback);
     method public final void removeOnFrameMetricsAvailableListener(android.view.Window.OnFrameMetricsAvailableListener);
     method public boolean requestFeature(int);
     method @NonNull public final <T extends android.view.View> T requireViewById(@IdRes int);
@@ -49886,6 +49519,7 @@
     method public abstract void takeKeyEvents(boolean);
     method public abstract void takeSurface(android.view.SurfaceHolder.Callback2);
     method public abstract void togglePanel(int, android.view.KeyEvent);
+    method public void unregisterScrollCaptureCallback(@NonNull android.view.ScrollCaptureCallback);
     field public static final int DECOR_CAPTION_SHADE_AUTO = 0; // 0x0
     field public static final int DECOR_CAPTION_SHADE_DARK = 2; // 0x2
     field public static final int DECOR_CAPTION_SHADE_LIGHT = 1; // 0x1
@@ -50126,9 +49760,12 @@
   }
 
   public interface WindowManager extends android.view.ViewManager {
+    method public default void addCrossWindowBlurEnabledListener(@NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @NonNull public default android.view.WindowMetrics getCurrentWindowMetrics();
     method @Deprecated public android.view.Display getDefaultDisplay();
     method @NonNull public default android.view.WindowMetrics getMaximumWindowMetrics();
+    method public default boolean isCrossWindowBlurEnabled();
+    method public default void removeCrossWindowBlurEnabledListener(@NonNull java.util.function.Consumer<java.lang.Boolean>);
     method public void removeViewImmediate(android.view.View);
   }
 
@@ -50153,12 +49790,14 @@
     method public final int copyFrom(android.view.WindowManager.LayoutParams);
     method public String debug(String);
     method public int describeContents();
+    method public int getBlurBehindRadius();
     method public int getColorMode();
     method public int getFitInsetsSides();
     method public int getFitInsetsTypes();
     method public final CharSequence getTitle();
     method public boolean isFitInsetsIgnoringVisibility();
     method public static boolean mayUseInputMethod(int);
+    method public void setBlurBehindRadius(@IntRange(from=0) int);
     method public void setColorMode(int);
     method public void setFitInsetsIgnoringVisibility(boolean);
     method public void setFitInsetsSides(int);
@@ -50269,7 +49908,6 @@
     field @Deprecated public static final int TYPE_TOAST = 2005; // 0x7d5
     field public static final int TYPE_WALLPAPER = 2013; // 0x7dd
     field public float alpha;
-    field public int blurBehindRadius;
     field public float buttonBrightness;
     field public float dimAmount;
     field public int flags;
@@ -50434,7 +50072,7 @@
     method public boolean canOpenPopup();
     method public int describeContents();
     method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String);
-    method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(String);
+    method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(@NonNull String);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
     method public android.view.accessibility.AccessibilityNodeInfo focusSearch(int);
     method public java.util.List<android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction> getActionList();
@@ -51696,7 +51334,6 @@
     method public int describeContents();
     method public void dump(android.util.Printer, String);
     method public android.content.ComponentName getComponent();
-    method public int getConfigChanges();
     method public String getId();
     method public int getIsDefaultResourceId();
     method public String getPackageName();
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index dd9582f..d6786f8 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -44,6 +44,14 @@
 
 }
 
+package android.app.usage {
+
+  public class NetworkStatsManager {
+    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyNetworkStatus(@NonNull java.util.List<android.net.Network>, @NonNull java.util.List<android.net.NetworkStateSnapshot>, @Nullable String, @NonNull java.util.List<android.net.UnderlyingNetworkInfo>);
+  }
+
+}
+
 package android.content {
 
   public abstract class Context {
@@ -163,30 +171,20 @@
 
 package android.net {
 
-  public final class ConnectivityFrameworkInitializer {
-    method public static void registerServiceWrappers();
-  }
-
-  public class ConnectivityManager {
-    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
-    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @Nullable android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
-    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
-  }
-
   public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
     method public int getResourceId();
   }
 
-  public final class NetworkAgentConfig implements android.os.Parcelable {
-    method @Nullable public String getSubscriberId();
-  }
-
-  public static final class NetworkAgentConfig.Builder {
-    method @NonNull public android.net.NetworkAgentConfig.Builder setSubscriberId(@Nullable String);
-  }
-
-  public final class NetworkCapabilities implements android.os.Parcelable {
-    field public static final int TRANSPORT_TEST = 7; // 0x7
+  public final class NetworkStateSnapshot implements android.os.Parcelable {
+    ctor public NetworkStateSnapshot(@NonNull android.net.Network, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, @Nullable String, int);
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkStateSnapshot> CREATOR;
+    field public final int legacyType;
+    field @NonNull public final android.net.LinkProperties linkProperties;
+    field @NonNull public final android.net.Network network;
+    field @NonNull public final android.net.NetworkCapabilities networkCapabilities;
+    field @Nullable public final String subscriberId;
   }
 
   public class NetworkWatchlistManager {
@@ -197,33 +195,6 @@
     method public static void setHttpProxyConfiguration(@Nullable android.net.ProxyInfo);
   }
 
-  public final class TcpRepairWindow {
-    ctor public TcpRepairWindow(int, int, int, int, int, int);
-    field public final int maxWindow;
-    field public final int rcvWnd;
-    field public final int rcvWndScale;
-    field public final int rcvWup;
-    field public final int sndWl1;
-    field public final int sndWnd;
-  }
-
-  public final class TestNetworkInterface implements android.os.Parcelable {
-    ctor public TestNetworkInterface(@NonNull android.os.ParcelFileDescriptor, @NonNull String);
-    method public int describeContents();
-    method @NonNull public android.os.ParcelFileDescriptor getFileDescriptor();
-    method @NonNull public String getInterfaceName();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.TestNetworkInterface> CREATOR;
-  }
-
-  public class TestNetworkManager {
-    method @NonNull public android.net.TestNetworkInterface createTapInterface();
-    method @NonNull public android.net.TestNetworkInterface createTunInterface(@NonNull java.util.Collection<android.net.LinkAddress>);
-    method public void setupTestNetwork(@NonNull String, @NonNull android.os.IBinder);
-    method public void teardownTestNetwork(@NonNull android.net.Network);
-    field public static final String TEST_TAP_PREFIX = "testtap";
-  }
-
   public final class UnderlyingNetworkInfo implements android.os.Parcelable {
     ctor public UnderlyingNetworkInfo(int, @NonNull String, @NonNull java.util.List<java.lang.String>);
     method public int describeContents();
@@ -234,14 +205,6 @@
     field @NonNull public final java.util.List<java.lang.String> underlyingIfaces;
   }
 
-  public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo {
-    ctor public VpnTransportInfo(int);
-    method public int describeContents();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.VpnTransportInfo> CREATOR;
-    field public final int type;
-  }
-
 }
 
 package android.os {
@@ -275,6 +238,16 @@
 
 }
 
+package android.os.storage {
+
+  public class StorageManager {
+    method public void notifyAppIoBlocked(@NonNull java.util.UUID, int, int, int);
+    method public void notifyAppIoResumed(@NonNull java.util.UUID, int, int, int);
+    field public static final int APP_IO_BLOCKED_REASON_TRANSCODING = 0; // 0x0
+  }
+
+}
+
 package android.provider {
 
   public final class DeviceConfig {
diff --git a/core/api/removed.txt b/core/api/removed.txt
index 990388a..a99178d 100644
--- a/core/api/removed.txt
+++ b/core/api/removed.txt
@@ -241,12 +241,6 @@
 
 package android.net {
 
-  public class ConnectivityManager {
-    method @Deprecated public boolean requestRouteToHost(int, int);
-    method @Deprecated public int startUsingNetworkFeature(int, String);
-    method @Deprecated public int stopUsingNetworkFeature(int, String);
-  }
-
   @Deprecated public class NetworkBadging {
     method @NonNull public static android.graphics.drawable.Drawable getWifiIcon(@IntRange(from=0, to=4) int, int, @Nullable android.content.res.Resources.Theme);
     field public static final int BADGING_4K = 30; // 0x1e
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index ff4fc95..998b114 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -27,10 +27,12 @@
     field public static final String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK";
     field public static final String AMBIENT_WALLPAPER = "android.permission.AMBIENT_WALLPAPER";
     field public static final String APPROVE_INCIDENT_REPORTS = "android.permission.APPROVE_INCIDENT_REPORTS";
+    field public static final String BACKGROUND_CAMERA = "android.permission.BACKGROUND_CAMERA";
     field public static final String BACKUP = "android.permission.BACKUP";
     field public static final String BATTERY_PREDICTION = "android.permission.BATTERY_PREDICTION";
     field public static final String BIND_ATTENTION_SERVICE = "android.permission.BIND_ATTENTION_SERVICE";
     field public static final String BIND_AUGMENTED_AUTOFILL_SERVICE = "android.permission.BIND_AUGMENTED_AUTOFILL_SERVICE";
+    field public static final String BIND_CALL_DIAGNOSTIC_SERVICE = "android.permission.BIND_CALL_DIAGNOSTIC_SERVICE";
     field public static final String BIND_CELL_BROADCAST_SERVICE = "android.permission.BIND_CELL_BROADCAST_SERVICE";
     field @Deprecated public static final String BIND_CONNECTION_SERVICE = "android.permission.BIND_CONNECTION_SERVICE";
     field public static final String BIND_CONTENT_CAPTURE_SERVICE = "android.permission.BIND_CONTENT_CAPTURE_SERVICE";
@@ -152,6 +154,7 @@
     field public static final String MANAGE_USB = "android.permission.MANAGE_USB";
     field public static final String MANAGE_USERS = "android.permission.MANAGE_USERS";
     field public static final String MANAGE_USER_OEM_UNLOCK_STATE = "android.permission.MANAGE_USER_OEM_UNLOCK_STATE";
+    field public static final String MANAGE_WIFI_COUNTRY_CODE = "android.permission.MANAGE_WIFI_COUNTRY_CODE";
     field public static final String MODIFY_APPWIDGET_BIND_PERMISSIONS = "android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS";
     field public static final String MODIFY_AUDIO_ROUTING = "android.permission.MODIFY_AUDIO_ROUTING";
     field public static final String MODIFY_CELL_BROADCASTS = "android.permission.MODIFY_CELL_BROADCASTS";
@@ -176,6 +179,7 @@
     field public static final String OBSERVE_APP_USAGE = "android.permission.OBSERVE_APP_USAGE";
     field public static final String OBSERVE_NETWORK_POLICY = "android.permission.OBSERVE_NETWORK_POLICY";
     field public static final String OBSERVE_ROLE_HOLDERS = "android.permission.OBSERVE_ROLE_HOLDERS";
+    field public static final String OBSERVE_SENSOR_PRIVACY = "android.permission.OBSERVE_SENSOR_PRIVACY";
     field public static final String OPEN_ACCESSIBILITY_DETAILS_SETTINGS = "android.permission.OPEN_ACCESSIBILITY_DETAILS_SETTINGS";
     field public static final String OVERRIDE_WIFI_CONFIG = "android.permission.OVERRIDE_WIFI_CONFIG";
     field public static final String PACKAGE_VERIFICATION_AGENT = "android.permission.PACKAGE_VERIFICATION_AGENT";
@@ -214,6 +218,7 @@
     field public static final String RECEIVE_DEVICE_CUSTOMIZATION_READY = "android.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY";
     field public static final String RECEIVE_EMERGENCY_BROADCAST = "android.permission.RECEIVE_EMERGENCY_BROADCAST";
     field public static final String RECEIVE_WIFI_CREDENTIAL_CHANGE = "android.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE";
+    field public static final String RECORD_BACKGROUND_AUDIO = "android.permission.RECORD_BACKGROUND_AUDIO";
     field public static final String RECOVERY = "android.permission.RECOVERY";
     field public static final String RECOVER_KEYSTORE = "android.permission.RECOVER_KEYSTORE";
     field public static final String REGISTER_CALL_PROVIDER = "android.permission.REGISTER_CALL_PROVIDER";
@@ -352,6 +357,7 @@
     field public static final int config_systemContacts = 17039403; // 0x104002b
     field public static final int config_systemGallery = 17039399; // 0x1040027
     field public static final int config_systemShell = 17039402; // 0x104002a
+    field public static final int config_systemSpeechRecognizer = 17039406; // 0x104002e
   }
 
   public static final class R.style {
@@ -418,6 +424,9 @@
     method @Nullable public static String opToPermission(@NonNull String);
     method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setMode(@NonNull String, int, @Nullable String, int);
     method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setUidMode(@NonNull String, int, int);
+    field public static final int HISTORY_FLAGS_ALL = 3; // 0x3
+    field public static final int HISTORY_FLAG_AGGREGATE = 1; // 0x1
+    field public static final int HISTORY_FLAG_DISCRETE = 2; // 0x2
     field public static final String OPSTR_ACCEPT_HANDOVER = "android:accept_handover";
     field public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility";
     field public static final String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications";
@@ -531,9 +540,14 @@
     method public long getAccessDuration(int, int, int);
     method public long getBackgroundAccessCount(int);
     method public long getBackgroundAccessDuration(int);
+    method @NonNull public java.util.List<android.app.AppOpsManager.AttributedOpEntry> getBackgroundDiscreteAccesses(int);
     method public long getBackgroundRejectCount(int);
+    method @NonNull public android.app.AppOpsManager.AttributedOpEntry getDiscreteAccessAt(@IntRange(from=0) int);
+    method @IntRange(from=0) public int getDiscreteAccessCount();
+    method @NonNull public java.util.List<android.app.AppOpsManager.AttributedOpEntry> getDiscreteAccesses(int, int, int);
     method public long getForegroundAccessCount(int);
     method public long getForegroundAccessDuration(int);
+    method @NonNull public java.util.List<android.app.AppOpsManager.AttributedOpEntry> getForegroundDiscreteAccesses(int);
     method public long getForegroundRejectCount(int);
     method @NonNull public String getOpName();
     method public long getRejectCount(int, int, int);
@@ -560,6 +574,7 @@
     method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest build();
     method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setAttributionTag(@Nullable String);
     method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setFlags(int);
+    method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setHistoryFlags(int);
     method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setOpNames(@Nullable java.util.List<java.lang.String>);
     method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setPackageName(@Nullable String);
     method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setUid(int);
@@ -641,8 +656,8 @@
     method public static android.app.BroadcastOptions makeBasic();
     method @RequiresPermission(android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND) public void setBackgroundActivityStartsAllowed(boolean);
     method public void setDontSendToRestrictedApps(boolean);
-    method @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppWhitelistDuration(long);
-    method @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppWhitelistDuration(int, long);
+    method @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppAllowlist(long, int, int, @Nullable String);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppWhitelistDuration(long);
     method public android.os.Bundle toBundle();
   }
 
@@ -853,13 +868,6 @@
     method public void onVrStateChanged(boolean);
   }
 
-  public final class WallpaperColors implements android.os.Parcelable {
-    ctor public WallpaperColors(@NonNull android.graphics.Color, @Nullable android.graphics.Color, @Nullable android.graphics.Color, int);
-    method public int getColorHints();
-    field public static final int HINT_SUPPORTS_DARK_TEXT = 1; // 0x1
-    field public static final int HINT_SUPPORTS_DARK_THEME = 2; // 0x2
-  }
-
   public final class WallpaperInfo implements android.os.Parcelable {
     method public boolean supportsAmbientMode();
   }
@@ -884,7 +892,7 @@
   public class DevicePolicyManager {
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public boolean getBluetoothContactSharingDisabled(@NonNull android.os.UserHandle);
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwner();
-    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.content.ComponentName getDeviceOwnerComponentOnAnyUser();
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, "android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"}) public android.content.ComponentName getDeviceOwnerComponentOnAnyUser();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwnerNameOnAnyUser();
     method @Nullable public CharSequence getDeviceOwnerOrganizationName();
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.UserHandle getDeviceOwnerUser();
@@ -957,6 +965,9 @@
 
 package android.app.assist {
 
+  public class ActivityId {
+  }
+
   public static class AssistStructure.ViewNode {
     ctor public AssistStructure.ViewNode();
   }
@@ -1887,11 +1898,18 @@
     field public static final int ACCESS_REJECTED = 2; // 0x2
     field public static final int ACCESS_UNKNOWN = 0; // 0x0
     field public static final String ACTION_SILENCE_MODE_CHANGED = "android.bluetooth.device.action.SILENCE_MODE_CHANGED";
+    field public static final String DEVICE_TYPE_DEFAULT = "Default";
+    field public static final String DEVICE_TYPE_UNTETHERED_HEADSET = "Untethered Headset";
+    field public static final String DEVICE_TYPE_WATCH = "Watch";
     field public static final int METADATA_COMPANION_APP = 4; // 0x4
+    field public static final int METADATA_DEVICE_TYPE = 17; // 0x11
     field public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16; // 0x10
     field public static final int METADATA_HARDWARE_VERSION = 3; // 0x3
     field public static final int METADATA_IS_UNTETHERED_HEADSET = 6; // 0x6
+    field public static final int METADATA_MAIN_BATTERY = 18; // 0x12
+    field public static final int METADATA_MAIN_CHARGING = 19; // 0x13
     field public static final int METADATA_MAIN_ICON = 5; // 0x5
+    field public static final int METADATA_MAIN_LOW_BATTERY_THRESHOLD = 20; // 0x14
     field public static final int METADATA_MANUFACTURER_NAME = 0; // 0x0
     field public static final int METADATA_MAX_LENGTH = 2048; // 0x800
     field public static final int METADATA_MODEL_NAME = 1; // 0x1
@@ -1899,12 +1917,15 @@
     field public static final int METADATA_UNTETHERED_CASE_BATTERY = 12; // 0xc
     field public static final int METADATA_UNTETHERED_CASE_CHARGING = 15; // 0xf
     field public static final int METADATA_UNTETHERED_CASE_ICON = 9; // 0x9
+    field public static final int METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD = 23; // 0x17
     field public static final int METADATA_UNTETHERED_LEFT_BATTERY = 10; // 0xa
     field public static final int METADATA_UNTETHERED_LEFT_CHARGING = 13; // 0xd
     field public static final int METADATA_UNTETHERED_LEFT_ICON = 7; // 0x7
+    field public static final int METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD = 21; // 0x15
     field public static final int METADATA_UNTETHERED_RIGHT_BATTERY = 11; // 0xb
     field public static final int METADATA_UNTETHERED_RIGHT_CHARGING = 14; // 0xe
     field public static final int METADATA_UNTETHERED_RIGHT_ICON = 8; // 0x8
+    field public static final int METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD = 22; // 0x16
   }
 
   public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
@@ -2461,10 +2482,10 @@
   }
 
   public static class PackageInstaller.Session implements java.io.Closeable {
-    method @RequiresPermission("com.android.permission.USE_INSTALLER_V2") public void addFile(int, @NonNull String, long, @NonNull byte[], @Nullable byte[]);
+    method public void addFile(int, @NonNull String, long, @NonNull byte[], @Nullable byte[]);
     method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void commitTransferred(@NonNull android.content.IntentSender);
-    method @Nullable @RequiresPermission("com.android.permission.USE_INSTALLER_V2") public android.content.pm.DataLoaderParams getDataLoaderParams();
-    method @RequiresPermission("com.android.permission.USE_INSTALLER_V2") public void removeFile(int, @NonNull String);
+    method @Nullable public android.content.pm.DataLoaderParams getDataLoaderParams();
+    method public void removeFile(int, @NonNull String);
   }
 
   public static class PackageInstaller.SessionInfo implements android.os.Parcelable {
@@ -2485,7 +2506,7 @@
   public static class PackageInstaller.SessionParams implements android.os.Parcelable {
     method @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) public void setAllocateAggressive(boolean);
     method @Deprecated public void setAllowDowngrade(boolean);
-    method @RequiresPermission(allOf={android.Manifest.permission.INSTALL_PACKAGES, "com.android.permission.USE_INSTALLER_V2"}) public void setDataLoaderParams(@NonNull android.content.pm.DataLoaderParams);
+    method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setDataLoaderParams(@NonNull android.content.pm.DataLoaderParams);
     method public void setDontKillApp(boolean);
     method public void setEnableRollback(boolean);
     method public void setEnableRollback(boolean, int);
@@ -2550,10 +2571,10 @@
     field public static final String EXTRA_REQUEST_PERMISSIONS_NAMES = "android.content.pm.extra.REQUEST_PERMISSIONS_NAMES";
     field public static final String EXTRA_REQUEST_PERMISSIONS_RESULTS = "android.content.pm.extra.REQUEST_PERMISSIONS_RESULTS";
     field public static final String FEATURE_BROADCAST_RADIO = "android.hardware.broadcastradio";
+    field public static final String FEATURE_CAMERA_TOGGLE = "android.hardware.camera.toggle";
     field public static final String FEATURE_CONTEXT_HUB = "android.hardware.context_hub";
-    field public static final String FEATURE_CROSS_LAYER_BLUR = "android.software.cross_layer_blur";
-    field @Deprecated public static final String FEATURE_INCREMENTAL_DELIVERY = "android.software.incremental_delivery";
-    field public static final String FEATURE_INCREMENTAL_DELIVERY_VERSION = "android.software.incremental_delivery_version";
+    field public static final String FEATURE_INCREMENTAL_DELIVERY = "android.software.incremental_delivery";
+    field public static final String FEATURE_MICROPHONE_TOGGLE = "android.hardware.microphone.toggle";
     field public static final String FEATURE_REBOOT_ESCROW = "android.hardware.reboot_escrow";
     field public static final String FEATURE_TELEPHONY_CARRIERLOCK = "android.hardware.telephony.carrierlock";
     field public static final String FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION = "android.hardware.telephony.ims.singlereg";
@@ -2565,7 +2586,6 @@
     field public static final int FLAG_PERMISSION_ONE_TIME = 65536; // 0x10000
     field public static final int FLAG_PERMISSION_POLICY_FIXED = 4; // 0x4
     field public static final int FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT = 2048; // 0x800
-    field public static final int FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT = 262144; // 0x40000
     field public static final int FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT = 4096; // 0x1000
     field public static final int FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT = 8192; // 0x2000
     field public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 64; // 0x40
@@ -2751,6 +2771,15 @@
 
 package android.content.pm.verify.domain {
 
+  public final class DomainOwner implements android.os.Parcelable {
+    ctor public DomainOwner(@NonNull String, boolean);
+    method public int describeContents();
+    method @NonNull public String getPackageName();
+    method public boolean isOverrideable();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.verify.domain.DomainOwner> CREATOR;
+  }
+
   public final class DomainVerificationInfo implements android.os.Parcelable {
     method public int describeContents();
     method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getHostToStateMap();
@@ -2763,6 +2792,7 @@
   public interface DomainVerificationManager {
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.DOMAIN_VERIFICATION_AGENT, android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION}) public android.content.pm.verify.domain.DomainVerificationInfo getDomainVerificationInfo(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
     method @Nullable @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION) public android.content.pm.verify.domain.DomainVerificationUserSelection getDomainVerificationUserSelection(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION) public java.util.List<android.content.pm.verify.domain.DomainOwner> getOwnersForDomain(@NonNull String);
     method @NonNull @RequiresPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT) public java.util.List<java.lang.String> getValidVerificationPackageNames();
     method public static boolean isStateModifiable(int);
     method public static boolean isStateVerified(int);
@@ -2784,13 +2814,16 @@
 
   public final class DomainVerificationUserSelection implements android.os.Parcelable {
     method public int describeContents();
-    method @NonNull public java.util.Map<java.lang.String,java.lang.Boolean> getHostToUserSelectionMap();
+    method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getHostToStateMap();
     method @NonNull public java.util.UUID getIdentifier();
     method @NonNull public String getPackageName();
     method @NonNull public android.os.UserHandle getUser();
     method @NonNull public boolean isLinkHandlingAllowed();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.verify.domain.DomainVerificationUserSelection> CREATOR;
+    field public static final int DOMAIN_STATE_NONE = 0; // 0x0
+    field public static final int DOMAIN_STATE_SELECTED = 1; // 0x1
+    field public static final int DOMAIN_STATE_VERIFIED = 2; // 0x2
   }
 
 }
@@ -2874,7 +2907,7 @@
   }
 
   public class FontManager {
-    method @Nullable public android.text.FontConfig getFontConfig();
+    method @NonNull public android.text.FontConfig getFontConfig();
     method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFamily(@NonNull android.graphics.fonts.FontFamilyUpdateRequest, @IntRange(from=0) int);
     method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFile(@NonNull android.graphics.fonts.FontFileUpdateRequest, @IntRange(from=0) int);
     method @Deprecated @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFile(@NonNull android.os.ParcelFileDescriptor, @NonNull byte[], @IntRange(from=0) int);
@@ -2908,6 +2941,22 @@
     method public boolean injectSensorData(android.hardware.Sensor, float[], int, long);
   }
 
+  public final class SensorPrivacyManager {
+    method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(int, @NonNull android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener);
+    method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(int, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener);
+    method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public boolean isSensorPrivacyEnabled(int);
+    method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void removeSensorPrivacyListener(@NonNull android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener);
+  }
+
+  public static interface SensorPrivacyManager.OnSensorPrivacyChangedListener {
+    method public void onSensorPrivacyChanged(boolean);
+  }
+
+  public static class SensorPrivacyManager.Sensors {
+    field public static final int CAMERA = 2; // 0x2
+    field public static final int MICROPHONE = 1; // 0x1
+  }
+
 }
 
 package android.hardware.biometrics {
@@ -5053,9 +5102,10 @@
   }
 
   public static class AudioTrack.TunerConfiguration {
-    ctor @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public AudioTrack.TunerConfiguration(@IntRange(from=1) int, @IntRange(from=1) int);
+    ctor @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public AudioTrack.TunerConfiguration(@IntRange(from=0) int, @IntRange(from=1) int);
     method @IntRange(from=1) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getContentId();
     method @IntRange(from=1) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getSyncId();
+    field public static final int CONTENT_ID_NONE = 0; // 0x0
   }
 
   public class HwAudioSource {
@@ -7063,102 +7113,6 @@
 
 package android.net {
 
-  public class CaptivePortal implements android.os.Parcelable {
-    method public void logEvent(int, @NonNull String);
-    method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void reevaluateNetwork();
-    method public void useNetwork();
-    field public static final int APP_REQUEST_REEVALUATION_REQUIRED = 100; // 0x64
-    field public static final int APP_RETURN_DISMISSED = 0; // 0x0
-    field public static final int APP_RETURN_UNWANTED = 1; // 0x1
-    field public static final int APP_RETURN_WANTED_AS_IS = 2; // 0x2
-  }
-
-  public final class CaptivePortalData implements android.os.Parcelable {
-    method public int describeContents();
-    method public long getByteLimit();
-    method public long getExpiryTimeMillis();
-    method public long getRefreshTimeMillis();
-    method @Nullable public android.net.Uri getUserPortalUrl();
-    method public int getUserPortalUrlSource();
-    method @Nullable public String getVenueFriendlyName();
-    method @Nullable public android.net.Uri getVenueInfoUrl();
-    method public int getVenueInfoUrlSource();
-    method public boolean isCaptive();
-    method public boolean isSessionExtendable();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final int CAPTIVE_PORTAL_DATA_SOURCE_OTHER = 0; // 0x0
-    field public static final int CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT = 1; // 0x1
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortalData> CREATOR;
-  }
-
-  public static class CaptivePortalData.Builder {
-    ctor public CaptivePortalData.Builder();
-    ctor public CaptivePortalData.Builder(@Nullable android.net.CaptivePortalData);
-    method @NonNull public android.net.CaptivePortalData build();
-    method @NonNull public android.net.CaptivePortalData.Builder setBytesRemaining(long);
-    method @NonNull public android.net.CaptivePortalData.Builder setCaptive(boolean);
-    method @NonNull public android.net.CaptivePortalData.Builder setExpiryTime(long);
-    method @NonNull public android.net.CaptivePortalData.Builder setRefreshTime(long);
-    method @NonNull public android.net.CaptivePortalData.Builder setSessionExtendable(boolean);
-    method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri);
-    method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri, int);
-    method @NonNull public android.net.CaptivePortalData.Builder setVenueFriendlyName(@Nullable String);
-    method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri);
-    method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri, int);
-  }
-
-  public class ConnectivityManager {
-    method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createNattKeepalive(@NonNull android.net.Network, @NonNull android.os.ParcelFileDescriptor, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
-    method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull java.net.Socket, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String getCaptivePortalServerUrl();
-    method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
-    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public int registerNetworkProvider(@NonNull android.net.NetworkProvider);
-    method public void registerQosCallback(@NonNull android.net.QosSocketInfo, @NonNull android.net.QosCallback, @NonNull java.util.concurrent.Executor);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
-    method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void requestNetwork(@NonNull android.net.NetworkRequest, int, int, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
-    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_AIRPLANE_MODE, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean);
-    method @RequiresPermission(android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE) public void setOemNetworkPreference(@NonNull android.net.OemNetworkPreferences, @Nullable java.util.concurrent.Executor, @Nullable android.net.ConnectivityManager.OnSetOemNetworkPreferenceListener);
-    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public boolean shouldAvoidBadWifi();
-    method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
-    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public void unregisterNetworkProvider(@NonNull android.net.NetworkProvider);
-    method public void unregisterQosCallback(@NonNull android.net.QosCallback);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
-    field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
-    field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
-    field public static final int TETHERING_BLUETOOTH = 2; // 0x2
-    field public static final int TETHERING_USB = 1; // 0x1
-    field public static final int TETHERING_WIFI = 0; // 0x0
-    field @Deprecated public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13; // 0xd
-    field @Deprecated public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
-    field @Deprecated public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
-    field public static final int TYPE_NONE = -1; // 0xffffffff
-    field @Deprecated public static final int TYPE_PROXY = 16; // 0x10
-    field @Deprecated public static final int TYPE_WIFI_P2P = 13; // 0xd
-  }
-
-  public static interface ConnectivityManager.OnSetOemNetworkPreferenceListener {
-    method public void onComplete();
-  }
-
-  @Deprecated public abstract static class ConnectivityManager.OnStartTetheringCallback {
-    ctor @Deprecated public ConnectivityManager.OnStartTetheringCallback();
-    method @Deprecated public void onTetheringFailed();
-    method @Deprecated public void onTetheringStarted();
-  }
-
-  @Deprecated public static interface ConnectivityManager.OnTetheringEntitlementResultListener {
-    method @Deprecated public void onTetheringEntitlementResult(int);
-  }
-
-  @Deprecated public abstract static class ConnectivityManager.OnTetheringEventCallback {
-    ctor @Deprecated public ConnectivityManager.OnTetheringEventCallback();
-    method @Deprecated public void onUpstreamChanged(@Nullable android.net.Network);
-  }
-
   public class DnsResolverServiceManager {
     method @NonNull @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public static android.os.IBinder getService(@NonNull android.content.Context);
   }
@@ -7176,48 +7130,6 @@
     method public void release();
   }
 
-  public final class InvalidPacketException extends java.lang.Exception {
-    ctor public InvalidPacketException(int);
-    method public int getError();
-    field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb
-    field public static final int ERROR_INVALID_LENGTH = -23; // 0xffffffe9
-    field public static final int ERROR_INVALID_PORT = -22; // 0xffffffea
-  }
-
-  public final class IpConfiguration implements android.os.Parcelable {
-    ctor public IpConfiguration();
-    ctor public IpConfiguration(@NonNull android.net.IpConfiguration);
-    method public int describeContents();
-    method @Nullable public android.net.ProxyInfo getHttpProxy();
-    method @NonNull public android.net.IpConfiguration.IpAssignment getIpAssignment();
-    method @NonNull public android.net.IpConfiguration.ProxySettings getProxySettings();
-    method @Nullable public android.net.StaticIpConfiguration getStaticIpConfiguration();
-    method public void setHttpProxy(@Nullable android.net.ProxyInfo);
-    method public void setIpAssignment(@NonNull android.net.IpConfiguration.IpAssignment);
-    method public void setProxySettings(@NonNull android.net.IpConfiguration.ProxySettings);
-    method public void setStaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.IpConfiguration> CREATOR;
-  }
-
-  public enum IpConfiguration.IpAssignment {
-    enum_constant public static final android.net.IpConfiguration.IpAssignment DHCP;
-    enum_constant public static final android.net.IpConfiguration.IpAssignment STATIC;
-    enum_constant public static final android.net.IpConfiguration.IpAssignment UNASSIGNED;
-  }
-
-  public enum IpConfiguration.ProxySettings {
-    enum_constant public static final android.net.IpConfiguration.ProxySettings NONE;
-    enum_constant public static final android.net.IpConfiguration.ProxySettings PAC;
-    enum_constant public static final android.net.IpConfiguration.ProxySettings STATIC;
-    enum_constant public static final android.net.IpConfiguration.ProxySettings UNASSIGNED;
-  }
-
-  public final class IpPrefix implements android.os.Parcelable {
-    ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
-    ctor public IpPrefix(@NonNull String);
-  }
-
   public final class IpSecManager {
     method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void applyTunnelModeTransform(@NonNull android.net.IpSecManager.IpSecTunnelInterface, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
     method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
@@ -7235,68 +7147,6 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecTransform buildTunnelModeTransform(@NonNull java.net.InetAddress, @NonNull android.net.IpSecManager.SecurityParameterIndex) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
   }
 
-  public class KeepalivePacketData {
-    ctor protected KeepalivePacketData(@NonNull java.net.InetAddress, @IntRange(from=0, to=65535) int, @NonNull java.net.InetAddress, @IntRange(from=0, to=65535) int, @NonNull byte[]) throws android.net.InvalidPacketException;
-    method @NonNull public java.net.InetAddress getDstAddress();
-    method public int getDstPort();
-    method @NonNull public byte[] getPacket();
-    method @NonNull public java.net.InetAddress getSrcAddress();
-    method public int getSrcPort();
-  }
-
-  public class LinkAddress implements android.os.Parcelable {
-    ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int);
-    ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int, long, long);
-    ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
-    ctor public LinkAddress(@NonNull String);
-    ctor public LinkAddress(@NonNull String, int, int);
-    method public long getDeprecationTime();
-    method public long getExpirationTime();
-    method public boolean isGlobalPreferred();
-    method public boolean isIpv4();
-    method public boolean isIpv6();
-    method public boolean isSameAddressAs(@Nullable android.net.LinkAddress);
-    field public static final long LIFETIME_PERMANENT = 9223372036854775807L; // 0x7fffffffffffffffL
-    field public static final long LIFETIME_UNKNOWN = -1L; // 0xffffffffffffffffL
-  }
-
-  public final class LinkProperties implements android.os.Parcelable {
-    ctor public LinkProperties(@Nullable android.net.LinkProperties);
-    ctor public LinkProperties(@Nullable android.net.LinkProperties, boolean);
-    method public boolean addDnsServer(@NonNull java.net.InetAddress);
-    method public boolean addLinkAddress(@NonNull android.net.LinkAddress);
-    method public boolean addPcscfServer(@NonNull java.net.InetAddress);
-    method @NonNull public java.util.List<java.net.InetAddress> getAddresses();
-    method @NonNull public java.util.List<java.lang.String> getAllInterfaceNames();
-    method @NonNull public java.util.List<android.net.LinkAddress> getAllLinkAddresses();
-    method @NonNull public java.util.List<android.net.RouteInfo> getAllRoutes();
-    method @Nullable public android.net.Uri getCaptivePortalApiUrl();
-    method @Nullable public android.net.CaptivePortalData getCaptivePortalData();
-    method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers();
-    method @Nullable public String getTcpBufferSizes();
-    method @NonNull public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
-    method public boolean hasGlobalIpv6Address();
-    method public boolean hasIpv4Address();
-    method public boolean hasIpv4DefaultRoute();
-    method public boolean hasIpv4DnsServer();
-    method public boolean hasIpv6DefaultRoute();
-    method public boolean hasIpv6DnsServer();
-    method public boolean isIpv4Provisioned();
-    method public boolean isIpv6Provisioned();
-    method public boolean isProvisioned();
-    method public boolean isReachable(@NonNull java.net.InetAddress);
-    method public boolean removeDnsServer(@NonNull java.net.InetAddress);
-    method public boolean removeLinkAddress(@NonNull android.net.LinkAddress);
-    method public boolean removeRoute(@NonNull android.net.RouteInfo);
-    method public void setCaptivePortalApiUrl(@Nullable android.net.Uri);
-    method public void setCaptivePortalData(@Nullable android.net.CaptivePortalData);
-    method public void setPcscfServers(@NonNull java.util.Collection<java.net.InetAddress>);
-    method public void setPrivateDnsServerName(@Nullable String);
-    method public void setTcpBufferSizes(@Nullable String);
-    method public void setUsePrivateDns(boolean);
-    method public void setValidatedPrivateDnsServers(@NonNull java.util.Collection<java.net.InetAddress>);
-  }
-
   public final class MatchAllNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
     ctor public MatchAllNetworkSpecifier();
     method public int describeContents();
@@ -7304,104 +7154,6 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.net.MatchAllNetworkSpecifier> CREATOR;
   }
 
-  public final class NattKeepalivePacketData extends android.net.KeepalivePacketData implements android.os.Parcelable {
-    ctor public NattKeepalivePacketData(@NonNull java.net.InetAddress, int, @NonNull java.net.InetAddress, int, @NonNull byte[]) throws android.net.InvalidPacketException;
-    method public int describeContents();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.NattKeepalivePacketData> CREATOR;
-  }
-
-  public class Network implements android.os.Parcelable {
-    ctor public Network(@NonNull android.net.Network);
-    method public int getNetId();
-    method @NonNull public android.net.Network getPrivateDnsBypassingCopy();
-  }
-
-  public abstract class NetworkAgent {
-    ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, int, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
-    method @Nullable public android.net.Network getNetwork();
-    method public void markConnected();
-    method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
-    method public void onAutomaticReconnectDisabled();
-    method public void onNetworkUnwanted();
-    method public void onQosCallbackRegistered(int, @NonNull android.net.QosFilter);
-    method public void onQosCallbackUnregistered(int);
-    method public void onRemoveKeepalivePacketFilter(int);
-    method public void onSaveAcceptUnvalidated(boolean);
-    method public void onSignalStrengthThresholdsUpdated(@NonNull int[]);
-    method public void onStartSocketKeepalive(int, @NonNull java.time.Duration, @NonNull android.net.KeepalivePacketData);
-    method public void onStopSocketKeepalive(int);
-    method public void onValidationStatus(int, @Nullable android.net.Uri);
-    method @NonNull public android.net.Network register();
-    method public final void sendLinkProperties(@NonNull android.net.LinkProperties);
-    method public final void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities);
-    method public final void sendNetworkScore(@IntRange(from=0, to=99) int);
-    method public final void sendQosCallbackError(int, int);
-    method public final void sendQosSessionAvailable(int, int, @NonNull android.telephony.data.EpsBearerQosSessionAttributes);
-    method public final void sendQosSessionLost(int, int);
-    method public final void sendSocketKeepaliveEvent(int, int);
-    method public final void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
-    method public void unregister();
-    field public static final int VALIDATION_STATUS_NOT_VALID = 2; // 0x2
-    field public static final int VALIDATION_STATUS_VALID = 1; // 0x1
-  }
-
-  public final class NetworkAgentConfig implements android.os.Parcelable {
-    method public int describeContents();
-    method public int getLegacyType();
-    method @NonNull public String getLegacyTypeName();
-    method public boolean isExplicitlySelected();
-    method public boolean isPartialConnectivityAcceptable();
-    method public boolean isUnvalidatedConnectivityAcceptable();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkAgentConfig> CREATOR;
-  }
-
-  public static final class NetworkAgentConfig.Builder {
-    ctor public NetworkAgentConfig.Builder();
-    method @NonNull public android.net.NetworkAgentConfig build();
-    method @NonNull public android.net.NetworkAgentConfig.Builder setExplicitlySelected(boolean);
-    method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyType(int);
-    method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyTypeName(@NonNull String);
-    method @NonNull public android.net.NetworkAgentConfig.Builder setPartialConnectivityAcceptable(boolean);
-    method @NonNull public android.net.NetworkAgentConfig.Builder setUnvalidatedConnectivityAcceptable(boolean);
-  }
-
-  public final class NetworkCapabilities implements android.os.Parcelable {
-    ctor public NetworkCapabilities(@Nullable android.net.NetworkCapabilities, boolean);
-    method @NonNull public int[] getAdministratorUids();
-    method @Nullable public String getSsid();
-    method @NonNull public int[] getTransportTypes();
-    method public boolean isPrivateDnsBroken();
-    method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
-    field public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; // 0x1c
-    field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16
-    field public static final int NET_CAPABILITY_OEM_PRIVATE = 26; // 0x1a
-    field public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24; // 0x18
-    field public static final int NET_CAPABILITY_VEHICLE_INTERNAL = 27; // 0x1b
-  }
-
-  public static final class NetworkCapabilities.Builder {
-    ctor public NetworkCapabilities.Builder();
-    ctor public NetworkCapabilities.Builder(@NonNull android.net.NetworkCapabilities);
-    method @NonNull public android.net.NetworkCapabilities.Builder addCapability(int);
-    method @NonNull public android.net.NetworkCapabilities.Builder addTransportType(int);
-    method @NonNull public android.net.NetworkCapabilities build();
-    method @NonNull public android.net.NetworkCapabilities.Builder clearAll();
-    method @NonNull public android.net.NetworkCapabilities.Builder removeCapability(int);
-    method @NonNull public android.net.NetworkCapabilities.Builder removeTransportType(int);
-    method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAdministratorUids(@NonNull int[]);
-    method @NonNull public android.net.NetworkCapabilities.Builder setLinkDownstreamBandwidthKbps(int);
-    method @NonNull public android.net.NetworkCapabilities.Builder setLinkUpstreamBandwidthKbps(int);
-    method @NonNull public android.net.NetworkCapabilities.Builder setNetworkSpecifier(@Nullable android.net.NetworkSpecifier);
-    method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setOwnerUid(int);
-    method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorPackageName(@Nullable String);
-    method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorUid(int);
-    method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkCapabilities.Builder setSignalStrength(int);
-    method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setSsid(@Nullable String);
-    method @NonNull public android.net.NetworkCapabilities.Builder setTransportInfo(@Nullable android.net.TransportInfo);
-  }
-
   public class NetworkKey implements android.os.Parcelable {
     ctor public NetworkKey(android.net.WifiKey);
     method @Nullable public static android.net.NetworkKey createFromScanResult(@NonNull android.net.wifi.ScanResult);
@@ -7413,33 +7165,12 @@
     field public final android.net.WifiKey wifiKey;
   }
 
-  public class NetworkProvider {
-    ctor public NetworkProvider(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String);
-    method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void declareNetworkRequestUnfulfillable(@NonNull android.net.NetworkRequest);
-    method public int getProviderId();
-    method public void onNetworkRequestWithdrawn(@NonNull android.net.NetworkRequest);
-    method public void onNetworkRequested(@NonNull android.net.NetworkRequest, @IntRange(from=0, to=99) int, int);
-    field public static final int ID_NONE = -1; // 0xffffffff
-  }
-
   public abstract class NetworkRecommendationProvider {
     ctor public NetworkRecommendationProvider(android.content.Context, java.util.concurrent.Executor);
     method public final android.os.IBinder getBinder();
     method public abstract void onRequestScores(android.net.NetworkKey[]);
   }
 
-  public class NetworkReleasedException extends java.lang.Exception {
-  }
-
-  public class NetworkRequest implements android.os.Parcelable {
-    method @Nullable public String getRequestorPackageName();
-    method public int getRequestorUid();
-  }
-
-  public static class NetworkRequest.Builder {
-    method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
-  }
-
   public class NetworkScoreManager {
     method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public boolean clearScores() throws java.lang.SecurityException;
     method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public void disableScoring() throws java.lang.SecurityException;
@@ -7523,57 +7254,6 @@
     method @NonNull public android.net.OemNetworkPreferences.Builder clearNetworkPreference(@NonNull String);
   }
 
-  public abstract class QosCallback {
-    ctor public QosCallback();
-    method public void onError(@NonNull android.net.QosCallbackException);
-    method public void onQosSessionAvailable(@NonNull android.net.QosSession, @NonNull android.net.QosSessionAttributes);
-    method public void onQosSessionLost(@NonNull android.net.QosSession);
-  }
-
-  public static class QosCallback.QosCallbackRegistrationException extends java.lang.RuntimeException {
-  }
-
-  public final class QosCallbackException extends java.lang.Exception {
-  }
-
-  public abstract class QosFilter {
-    method @NonNull public abstract android.net.Network getNetwork();
-    method public abstract boolean matchesLocalAddress(@NonNull java.net.InetAddress, int, int);
-  }
-
-  public final class QosSession implements android.os.Parcelable {
-    ctor public QosSession(int, int);
-    method public int describeContents();
-    method public int getSessionId();
-    method public int getSessionType();
-    method public long getUniqueId();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSession> CREATOR;
-    field public static final int TYPE_EPS_BEARER = 1; // 0x1
-  }
-
-  public interface QosSessionAttributes {
-  }
-
-  public final class QosSocketInfo implements android.os.Parcelable {
-    ctor public QosSocketInfo(@NonNull android.net.Network, @NonNull java.net.Socket) throws java.io.IOException;
-    method public int describeContents();
-    method @NonNull public java.net.InetSocketAddress getLocalSocketAddress();
-    method @NonNull public android.net.Network getNetwork();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSocketInfo> CREATOR;
-  }
-
-  public final class RouteInfo implements android.os.Parcelable {
-    ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int);
-    ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int, int);
-    method public int getMtu();
-    method public int getType();
-    field public static final int RTN_THROW = 9; // 0x9
-    field public static final int RTN_UNICAST = 1; // 0x1
-    field public static final int RTN_UNREACHABLE = 7; // 0x7
-  }
-
   public class RssiCurve implements android.os.Parcelable {
     ctor public RssiCurve(int, int, byte[]);
     ctor public RssiCurve(int, int, byte[], int);
@@ -7605,53 +7285,6 @@
     field public final android.net.RssiCurve rssiCurve;
   }
 
-  public abstract class SocketKeepalive implements java.lang.AutoCloseable {
-    field public static final int SUCCESS = 0; // 0x0
-  }
-
-  public class SocketLocalAddressChangedException extends java.lang.Exception {
-  }
-
-  public class SocketNotBoundException extends java.lang.Exception {
-  }
-
-  public final class StaticIpConfiguration implements android.os.Parcelable {
-    ctor public StaticIpConfiguration();
-    ctor public StaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
-    method public void addDnsServer(@NonNull java.net.InetAddress);
-    method public void clear();
-    method public int describeContents();
-    method @NonNull public java.util.List<java.net.InetAddress> getDnsServers();
-    method @Nullable public String getDomains();
-    method @Nullable public java.net.InetAddress getGateway();
-    method @Nullable public android.net.LinkAddress getIpAddress();
-    method @NonNull public java.util.List<android.net.RouteInfo> getRoutes(@Nullable String);
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.StaticIpConfiguration> CREATOR;
-  }
-
-  public static final class StaticIpConfiguration.Builder {
-    ctor public StaticIpConfiguration.Builder();
-    method @NonNull public android.net.StaticIpConfiguration build();
-    method @NonNull public android.net.StaticIpConfiguration.Builder setDnsServers(@NonNull Iterable<java.net.InetAddress>);
-    method @NonNull public android.net.StaticIpConfiguration.Builder setDomains(@Nullable String);
-    method @NonNull public android.net.StaticIpConfiguration.Builder setGateway(@Nullable java.net.InetAddress);
-    method @NonNull public android.net.StaticIpConfiguration.Builder setIpAddress(@Nullable android.net.LinkAddress);
-  }
-
-  public final class TcpKeepalivePacketData extends android.net.KeepalivePacketData implements android.os.Parcelable {
-    ctor public TcpKeepalivePacketData(@NonNull java.net.InetAddress, int, @NonNull java.net.InetAddress, int, @NonNull byte[], int, int, int, int, int, int) throws android.net.InvalidPacketException;
-    method public int describeContents();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.TcpKeepalivePacketData> CREATOR;
-    field public final int ipTos;
-    field public final int ipTtl;
-    field public final int tcpAck;
-    field public final int tcpSeq;
-    field public final int tcpWindow;
-    field public final int tcpWindowScale;
-  }
-
   public class TrafficStats {
     method public static void setThreadStatsTagApp();
     method public static void setThreadStatsTagBackup();
@@ -7664,11 +7297,6 @@
     field public static final int TAG_SYSTEM_IMPERSONATION_RANGE_START = -256; // 0xffffff00
   }
 
-  public interface TransportInfo {
-    method public default boolean hasLocationSensitiveFields();
-    method @NonNull public default android.net.TransportInfo makeCopy(boolean);
-  }
-
   public abstract class Uri implements java.lang.Comparable<android.net.Uri> android.os.Parcelable {
     method @NonNull public String toSafeString();
   }
@@ -7692,23 +7320,6 @@
 
 }
 
-package android.net.apf {
-
-  public final class ApfCapabilities implements android.os.Parcelable {
-    ctor public ApfCapabilities(int, int, int);
-    method public int describeContents();
-    method public static boolean getApfDrop8023Frames();
-    method @NonNull public static int[] getApfEtherTypeBlackList();
-    method public boolean hasDataAccess();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.net.apf.ApfCapabilities> CREATOR;
-    field public final int apfPacketFormat;
-    field public final int apfVersionSupported;
-    field public final int maximumApfProgramSize;
-  }
-
-}
-
 package android.net.metrics {
 
   @Deprecated public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event {
@@ -8607,11 +8218,19 @@
     method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull String);
     method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull java.util.List<java.lang.String>);
     method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void removeFromWhitelist(@NonNull String);
-    method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(@NonNull String, long);
-    method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long whitelistAppTemporarilyForEvent(@NonNull String, int, @NonNull String);
+    method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(@NonNull String, long, int, @Nullable String);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(@NonNull String, long);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long whitelistAppTemporarilyForEvent(@NonNull String, int, @Nullable String);
+    method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long whitelistAppTemporarilyForEvent(@NonNull String, int, int, @Nullable String);
     field public static final int EVENT_MMS = 2; // 0x2
     field public static final int EVENT_SMS = 1; // 0x1
     field public static final int EVENT_UNSPECIFIED = 0; // 0x0
+    field public static final int REASON_ACTIVITY_RECOGNITION = 103; // 0x67
+    field public static final int REASON_GEOFENCING = 100; // 0x64
+    field public static final int REASON_OTHER = 1; // 0x1
+    field public static final int REASON_PUSH_MESSAGING = 101; // 0x65
+    field public static final int REASON_PUSH_MESSAGING_OVER_QUOTA = 102; // 0x66
+    field public static final int REASON_UNKNOWN = 0; // 0x0
     field public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED = 0; // 0x0
     field public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED = 1; // 0x1
   }
@@ -8760,13 +8379,13 @@
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.os.UserHandle createProfile(@NonNull String, @NonNull String, @NonNull java.util.Set<java.lang.String>) throws android.os.UserManager.UserOperationException;
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public java.util.List<android.os.UserHandle> getAllProfiles();
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public java.util.List<android.os.UserHandle> getEnabledProfiles();
-    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.UserHandle getProfileParent(@NonNull android.os.UserHandle);
+    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public android.os.UserHandle getProfileParent(@NonNull android.os.UserHandle);
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.os.UserHandle getRestrictedProfileParent();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountName();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.PersistableBundle getSeedAccountOptions();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountType();
-    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public long[] getSerialNumbersOfUsers(boolean);
-    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<android.os.UserHandle> getUserHandles(boolean);
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public long[] getSerialNumbersOfUsers(boolean);
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public java.util.List<android.os.UserHandle> getUserHandles(boolean);
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public android.graphics.Bitmap getUserIcon();
     method @Deprecated @android.os.UserManager.UserRestrictionSource @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public int getUserRestrictionSource(String, android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<android.os.UserManager.EnforcingUser> getUserRestrictionSources(String, android.os.UserHandle);
@@ -9204,6 +8823,7 @@
     field public static final String NAMESPACE_BIOMETRICS = "biometrics";
     field public static final String NAMESPACE_BLOBSTORE = "blobstore";
     field public static final String NAMESPACE_BLUETOOTH = "bluetooth";
+    field public static final String NAMESPACE_CLIPBOARD = "clipboard";
     field public static final String NAMESPACE_CONNECTIVITY = "connectivity";
     field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
     field @Deprecated public static final String NAMESPACE_DEX_BOOT = "dex_boot";
@@ -10427,10 +10047,10 @@
 
   public abstract class ExternalStorageService extends android.app.Service {
     ctor public ExternalStorageService();
+    method public void onAnrDelayStarted(@NonNull String, int, int, int);
     method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
     method public abstract void onEndSession(@NonNull String) throws java.io.IOException;
     method public void onFreeCache(@NonNull java.util.UUID, long) throws java.io.IOException;
-    method public long onGetAnrDelayMillis(@NonNull String, int);
     method public abstract void onStartSession(@NonNull String, int, @NonNull android.os.ParcelFileDescriptor, @NonNull java.io.File, @NonNull java.io.File) throws java.io.IOException;
     method public abstract void onVolumeStateChanged(@NonNull android.os.storage.StorageVolume) throws java.io.IOException;
     field public static final int FLAG_SESSION_ATTRIBUTE_INDEXABLE = 2; // 0x2
@@ -10628,7 +10248,7 @@
   public abstract class HotwordDetectionService extends android.app.Service {
     ctor public HotwordDetectionService();
     method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
-    method public void onDetectFromDspSource(int, @NonNull android.service.voice.HotwordDetectionService.DspHotwordDetectionCallback);
+    method public void onDetectFromDspSource(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, long, @NonNull android.service.voice.HotwordDetectionService.DspHotwordDetectionCallback);
     field public static final String SERVICE_INTERFACE = "android.service.voice.HotwordDetectionService";
   }
 
@@ -10740,6 +10360,16 @@
     ctor @Deprecated public Call.Listener();
   }
 
+  public abstract class CallDiagnosticService extends android.app.Service {
+    ctor public CallDiagnosticService();
+    method @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent);
+    method public abstract void onBluetoothCallQualityReportReceived(@NonNull android.telecom.BluetoothCallQualityReport);
+    method public abstract void onCallAudioStateChanged(@NonNull android.telecom.CallAudioState);
+    method @NonNull public abstract android.telecom.DiagnosticCall onInitializeDiagnosticCall(@NonNull android.telecom.Call.Details);
+    method public abstract void onRemoveDiagnosticCall(@NonNull android.telecom.DiagnosticCall);
+    field public static final String SERVICE_INTERFACE = "android.telecom.CallDiagnosticService";
+  }
+
   public static class CallScreeningService.CallResponse.Builder {
     method @NonNull @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT) public android.telecom.CallScreeningService.CallResponse.Builder setShouldScreenCallViaAudioProcessing(boolean);
   }
@@ -10763,7 +10393,7 @@
     method @Nullable public android.telecom.PhoneAccountHandle getPhoneAccountHandle();
     method @Nullable public final String getTelecomCallId();
     method @Deprecated public void onAudioStateChanged(android.telecom.AudioState);
-    method @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public void onCallFilteringCompleted(boolean, boolean, @Nullable android.telecom.CallScreeningService.CallResponse, boolean);
+    method @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public void onCallFilteringCompleted(@NonNull android.telecom.Connection.CallFilteringCompletionInfo);
     method public final void resetConnectionTime();
     method public void setCallDirection(int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public final void setConnectTimeMillis(@IntRange(from=0) long);
@@ -10772,6 +10402,9 @@
     method public void setTelecomCallId(@NonNull String);
     field public static final int CAPABILITY_CONFERENCE_HAS_NO_CHILDREN = 2097152; // 0x200000
     field public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 262144; // 0x40000
+    field public static final String EVENT_DEVICE_TO_DEVICE_MESSAGE = "android.telecom.event.DEVICE_TO_DEVICE_MESSAGE";
+    field public static final String EXTRA_DEVICE_TO_DEVICE_MESSAGE_TYPE = "android.telecom.extra.DEVICE_TO_DEVICE_MESSAGE_TYPE";
+    field public static final String EXTRA_DEVICE_TO_DEVICE_MESSAGE_VALUE = "android.telecom.extra.DEVICE_TO_DEVICE_MESSAGE_VALUE";
     field public static final String EXTRA_DISABLE_ADD_CALL = "android.telecom.extra.DISABLE_ADD_CALL";
     field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 1; // 0x1
     field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
@@ -10779,6 +10412,16 @@
     field public static final int PROPERTY_REMOTELY_HOSTED = 2048; // 0x800
   }
 
+  public static final class Connection.CallFilteringCompletionInfo implements android.os.Parcelable {
+    ctor public Connection.CallFilteringCompletionInfo(boolean, boolean, @Nullable android.telecom.CallScreeningService.CallResponse, @Nullable android.content.ComponentName);
+    method public int describeContents();
+    method @Nullable public android.telecom.CallScreeningService.CallResponse getCallResponse();
+    method @Nullable public android.content.ComponentName getCallScreeningComponent();
+    method public boolean isBlocked();
+    method public boolean isInContacts();
+    field @NonNull public static final android.os.Parcelable.Creator<android.telecom.Connection.CallFilteringCompletionInfo> CREATOR;
+  }
+
   public final class ConnectionRequest implements android.os.Parcelable {
     method @Nullable public String getTelecomCallId();
   }
@@ -10787,6 +10430,34 @@
     method public final void addExistingConnection(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.Connection, @NonNull android.telecom.Conference);
   }
 
+  public abstract class DiagnosticCall {
+    ctor public DiagnosticCall();
+    method public final void clearDiagnosticMessage(int);
+    method public final void displayDiagnosticMessage(int, @NonNull CharSequence);
+    method @NonNull public android.telecom.Call.Details getCallDetails();
+    method public abstract void onCallDetailsChanged(@NonNull android.telecom.Call.Details);
+    method @Nullable public abstract CharSequence onCallDisconnected(int, int);
+    method @Nullable public abstract CharSequence onCallDisconnected(@NonNull android.telephony.ims.ImsReasonInfo);
+    method public abstract void onCallQualityReceived(@NonNull android.telephony.CallQuality);
+    method public abstract void onReceiveDeviceToDeviceMessage(int, int);
+    method public final void sendDeviceToDeviceMessage(int, int);
+    field public static final int AUDIO_CODEC_AMR_NB = 3; // 0x3
+    field public static final int AUDIO_CODEC_AMR_WB = 2; // 0x2
+    field public static final int AUDIO_CODEC_EVS = 1; // 0x1
+    field public static final int BATTERY_STATE_CHARGING = 3; // 0x3
+    field public static final int BATTERY_STATE_GOOD = 2; // 0x2
+    field public static final int BATTERY_STATE_LOW = 1; // 0x1
+    field public static final int COVERAGE_GOOD = 2; // 0x2
+    field public static final int COVERAGE_POOR = 1; // 0x1
+    field public static final int MESSAGE_CALL_AUDIO_CODEC = 2; // 0x2
+    field public static final int MESSAGE_CALL_NETWORK_TYPE = 1; // 0x1
+    field public static final int MESSAGE_DEVICE_BATTERY_STATE = 3; // 0x3
+    field public static final int MESSAGE_DEVICE_NETWORK_COVERAGE = 4; // 0x4
+    field public static final int NETWORK_TYPE_IWLAN = 2; // 0x2
+    field public static final int NETWORK_TYPE_LTE = 1; // 0x1
+    field public static final int NETWORK_TYPE_NR = 3; // 0x3
+  }
+
   public abstract class InCallService extends android.app.Service {
     method @Deprecated public android.telecom.Phone getPhone();
     method @Deprecated public void onPhoneCreated(android.telecom.Phone);
@@ -10940,7 +10611,7 @@
   }
 
   public final class RemoteConnection {
-    method @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public void onCallFilteringCompleted(boolean, boolean, @Nullable android.telecom.CallScreeningService.CallResponse, boolean);
+    method @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public void onCallFilteringCompleted(@NonNull android.telecom.Connection.CallFilteringCompletionInfo);
     method @Deprecated public void setAudioState(android.telecom.AudioState);
   }
 
@@ -11121,6 +10792,10 @@
     field public static final String KEY_SUPPORT_CDMA_1X_VOICE_CALLS_BOOL = "support_cdma_1x_voice_calls_bool";
   }
 
+  public static final class CarrierConfigManager.Ims {
+    field public static final String KEY_PUBLISH_SERVICE_DESC_FEATURE_TAG_MAP_OVERRIDE_STRING_ARRAY = "ims.publish_service_desc_feature_tag_map_override_string_array";
+  }
+
   public static final class CarrierConfigManager.Wifi {
     field public static final String KEY_AVOID_5GHZ_SOFTAP_FOR_LAA_BOOL = "wifi.avoid_5ghz_softap_for_laa_bool";
     field public static final String KEY_AVOID_5GHZ_WIFI_DIRECT_FOR_LAA_BOOL = "wifi.avoid_5ghz_wifi_direct_for_laa_bool";
@@ -13752,7 +13427,7 @@
   }
 
   public static interface CapabilityExchangeEventListener.OptionsRequestCallback {
-    method public default void onRespondToCapabilityRequest(@NonNull android.telephony.ims.RcsContactUceCapability, boolean);
+    method public void onRespondToCapabilityRequest(@NonNull android.telephony.ims.RcsContactUceCapability, boolean);
     method public void onRespondToCapabilityRequestWithError(@IntRange(from=100, to=699) int, @NonNull String);
   }
 
@@ -14349,6 +14024,7 @@
 
   public final class ContentCaptureContext implements android.os.Parcelable {
     method @Nullable public android.content.ComponentName getActivityComponent();
+    method @Nullable public android.app.assist.ActivityId getActivityId();
     method public int getDisplayId();
     method public int getFlags();
     method @Nullable public android.view.contentcapture.ContentCaptureSessionId getParentSessionId();
@@ -14411,9 +14087,13 @@
 
   public final class UiTranslationManager {
     method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void finishTranslation(int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void finishTranslation(@NonNull android.app.assist.ActivityId);
     method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void pauseTranslation(int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void pauseTranslation(@NonNull android.app.assist.ActivityId);
     method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void resumeTranslation(int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void resumeTranslation(@NonNull android.app.assist.ActivityId);
     method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void startTranslation(@NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec, @NonNull java.util.List<android.view.autofill.AutofillId>, int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void startTranslation(@NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec, @NonNull java.util.List<android.view.autofill.AutofillId>, @NonNull android.app.assist.ActivityId);
   }
 
 }
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index f0a2a49..e4757e6 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -5,14 +5,17 @@
     field public static final String ACCESS_NOTIFICATIONS = "android.permission.ACCESS_NOTIFICATIONS";
     field public static final String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
     field public static final String APPROVE_INCIDENT_REPORTS = "android.permission.APPROVE_INCIDENT_REPORTS";
+    field public static final String BACKGROUND_CAMERA = "android.permission.BACKGROUND_CAMERA";
     field public static final String BIND_CELL_BROADCAST_SERVICE = "android.permission.BIND_CELL_BROADCAST_SERVICE";
     field public static final String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
     field public static final String BROADCAST_CLOSE_SYSTEM_DIALOGS = "android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS";
     field public static final String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE";
     field public static final String CLEAR_APP_USER_DATA = "android.permission.CLEAR_APP_USER_DATA";
+    field public static final String CLEAR_FREEZE_PERIOD = "android.permission.CLEAR_FREEZE_PERIOD";
     field public static final String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
     field public static final String CONTROL_DEVICE_LIGHTS = "android.permission.CONTROL_DEVICE_LIGHTS";
     field public static final String CONTROL_DEVICE_STATE = "android.permission.CONTROL_DEVICE_STATE";
+    field public static final String FORCE_DEVICE_POLICY_MANAGER_LOGS = "android.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS";
     field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
     field public static final String KEEP_UNINSTALLED_PACKAGES = "android.permission.KEEP_UNINSTALLED_PACKAGES";
     field @Deprecated public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
@@ -28,6 +31,7 @@
     field public static final String QUERY_USERS = "android.permission.QUERY_USERS";
     field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
     field public static final String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE";
+    field public static final String RECORD_BACKGROUND_AUDIO = "android.permission.RECORD_BACKGROUND_AUDIO";
     field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
     field public static final String RESET_APP_ERRORS = "android.permission.RESET_APP_ERRORS";
     field public static final String START_TASKS_FROM_RECENTS = "android.permission.START_TASKS_FROM_RECENTS";
@@ -91,6 +95,8 @@
     method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void addHomeVisibilityListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.HomeVisibilityListener);
     method public void alwaysShowUnsupportedCompileSdkWarning(android.content.ComponentName);
     method public long getTotalRam();
+    method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getUidProcessCapabilities(int);
+    method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getUidProcessState(int);
     method public void holdLock(android.os.IBinder, int);
     method public static boolean isHighEndGfx();
     method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void removeHomeVisibilityListener(@NonNull android.app.HomeVisibilityListener);
@@ -106,7 +112,10 @@
     field public static final int PROCESS_CAPABILITY_FOREGROUND_CAMERA = 2; // 0x2
     field public static final int PROCESS_CAPABILITY_FOREGROUND_LOCATION = 1; // 0x1
     field public static final int PROCESS_CAPABILITY_FOREGROUND_MICROPHONE = 4; // 0x4
+    field public static final int PROCESS_CAPABILITY_NETWORK = 8; // 0x8
     field public static final int PROCESS_CAPABILITY_NONE = 0; // 0x0
+    field public static final int PROCESS_STATE_FOREGROUND_SERVICE = 4; // 0x4
+    field public static final int PROCESS_STATE_TOP = 2; // 0x2
   }
 
   public static class ActivityManager.RunningAppProcessInfo implements android.os.Parcelable {
@@ -215,6 +224,9 @@
     field public static final int HISTORICAL_MODE_DISABLED = 0; // 0x0
     field public static final int HISTORICAL_MODE_ENABLED_ACTIVE = 1; // 0x1
     field public static final int HISTORICAL_MODE_ENABLED_PASSIVE = 2; // 0x2
+    field public static final int HISTORY_FLAGS_ALL = 3; // 0x3
+    field public static final int HISTORY_FLAG_AGGREGATE = 1; // 0x1
+    field public static final int HISTORY_FLAG_DISCRETE = 2; // 0x2
     field public static final String KEY_BG_STATE_SETTLE_TIME = "bg_state_settle_time";
     field public static final String KEY_FG_SERVICE_STATE_SETTLE_TIME = "fg_service_state_settle_time";
     field public static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time";
@@ -229,6 +241,7 @@
 
   public static final class AppOpsManager.HistoricalOps implements android.os.Parcelable {
     ctor public AppOpsManager.HistoricalOps(long, long);
+    method public void addDiscreteAccess(int, int, @NonNull String, @Nullable String, int, int, long, long);
     method public void increaseAccessCount(int, int, @NonNull String, @Nullable String, int, int, long);
     method public void increaseAccessDuration(int, int, @NonNull String, @Nullable String, int, int, long);
     method public void increaseRejectCount(int, int, @NonNull String, @Nullable String, int, int, long);
@@ -384,18 +397,27 @@
 
   public class DevicePolicyManager {
     method public int checkProvisioningPreCondition(@Nullable String, @NonNull String);
+    method @RequiresPermission(android.Manifest.permission.CLEAR_FREEZE_PERIOD) public void clearSystemUpdatePolicyFreezePeriodRecord();
     method @Nullable public android.os.UserHandle createAndProvisionManagedProfile(@NonNull android.app.admin.ManagedProfileProvisioningParams) throws android.app.admin.ProvisioningException;
+    method @RequiresPermission(android.Manifest.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS) public long forceNetworkLogs();
+    method @RequiresPermission("android.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 @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();
     method public long getLastNetworkLogRetrievalTime();
     method public long getLastSecurityLogRetrievalTime();
     method public java.util.List<java.lang.String> getOwnerInstalledCaCerts(@NonNull android.os.UserHandle);
     method public boolean isCurrentInputMethodSetByOwner();
     method public boolean isFactoryResetProtectionPolicySupported();
+    method @RequiresPermission(anyOf={"android.permission.MARK_DEVICE_ORGANIZATION_OWNED", "android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"}, conditional=true) public void markProfileOwnerOnOrganizationOwnedDevice(@NonNull android.content.ComponentName);
     method @NonNull public static String operationSafetyReasonToString(int);
     method @NonNull public static String operationToString(int);
     method @RequiresPermission("android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS") public void provisionFullyManagedDevice(@NonNull android.app.admin.FullyManagedDeviceProvisioningParams) throws android.app.admin.ProvisioningException;
     method @RequiresPermission("android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS") public void resetDefaultCrossProfileIntentFilters(int);
+    method @RequiresPermission(allOf={"android.permission.MANAGE_DEVICE_ADMINS", android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void setActiveAdmin(@NonNull android.content.ComponentName, boolean, int);
+    method @RequiresPermission("android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS") public boolean setDeviceOwner(@NonNull android.content.ComponentName, @Nullable String, int);
     method @RequiresPermission("android.permission.MANAGE_DEVICE_ADMINS") public void setNextOperationSafety(int, int);
     field public static final String ACTION_DATA_SHARING_RESTRICTION_APPLIED = "android.app.action.DATA_SHARING_RESTRICTION_APPLIED";
     field public static final int CODE_ACCOUNTS_NOT_EMPTY = 6; // 0x6
@@ -528,6 +550,15 @@
 
 }
 
+package android.app.assist {
+
+  public class ActivityId {
+    method public int getTaskId();
+    method @Nullable public android.os.IBinder getToken();
+  }
+
+}
+
 package android.app.blob {
 
   public class BlobStoreManager {
@@ -548,6 +579,16 @@
 
 }
 
+package android.app.contentsuggestions {
+
+  public final class ContentSuggestionsManager {
+    method @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_SUGGESTIONS) public void resetTemporaryService(int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_SUGGESTIONS) public void setDefaultServiceEnabled(int, boolean);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_SUGGESTIONS) public void setTemporaryService(int, @NonNull String, int);
+  }
+
+}
+
 package android.app.prediction {
 
   public final class AppPredictor {
@@ -681,6 +722,10 @@
     field public int privateFlags;
   }
 
+  public class CrossProfileApps {
+    method public boolean canConfigureInteractAcrossProfiles(@NonNull String);
+  }
+
   public class LauncherApps {
     ctor public LauncherApps(android.content.Context);
   }
@@ -704,8 +749,10 @@
     method public void holdLock(android.os.IBinder, int);
     method @RequiresPermission(android.Manifest.permission.KEEP_UNINSTALLED_PACKAGES) public void setKeepUninstalledPackages(@NonNull java.util.List<java.lang.String>);
     field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
+    field public static final String FEATURE_CAMERA_TOGGLE = "android.hardware.camera.toggle";
     field public static final String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption";
     field public static final String FEATURE_HDMI_CEC = "android.hardware.hdmi.cec";
+    field public static final String FEATURE_MICROPHONE_TOGGLE = "android.hardware.microphone.toggle";
     field public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED = 128; // 0x80
     field public static final int MATCH_KNOWN_PACKAGES = 4202496; // 0x402000
     field public static final String SYSTEM_SHARED_LIBRARY_SERVICES = "android.ext.services";
@@ -732,6 +779,65 @@
     ctor public ShortcutManager(android.content.Context);
   }
 
+  public class UserInfo implements android.os.Parcelable {
+    ctor public UserInfo(int, String, int);
+    ctor public UserInfo(int, String, String, int);
+    ctor public UserInfo(int, String, String, int, String);
+    ctor @Deprecated public UserInfo();
+    ctor public UserInfo(android.content.pm.UserInfo);
+    method public boolean canHaveProfile();
+    method public int describeContents();
+    method public android.os.UserHandle getUserHandle();
+    method public boolean isAdmin();
+    method public boolean isDemo();
+    method public boolean isEnabled();
+    method public boolean isEphemeral();
+    method public boolean isFull();
+    method public boolean isGuest();
+    method public boolean isInitialized();
+    method public boolean isManagedProfile();
+    method public boolean isPrimary();
+    method public boolean isProfile();
+    method public boolean isQuietModeEnabled();
+    method public boolean isRestricted();
+    method public boolean isSystemOnly();
+    method public static boolean isSystemOnly(int);
+    method public boolean supportsSwitchTo();
+    method public boolean supportsSwitchToByUser();
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.UserInfo> CREATOR;
+    field public static final int FLAG_ADMIN = 2; // 0x2
+    field @Deprecated public static final int FLAG_DEMO = 512; // 0x200
+    field public static final int FLAG_DISABLED = 64; // 0x40
+    field public static final int FLAG_EPHEMERAL = 256; // 0x100
+    field public static final int FLAG_FULL = 1024; // 0x400
+    field @Deprecated public static final int FLAG_GUEST = 4; // 0x4
+    field public static final int FLAG_INITIALIZED = 16; // 0x10
+    field @Deprecated public static final int FLAG_MANAGED_PROFILE = 32; // 0x20
+    field public static final int FLAG_PRIMARY = 1; // 0x1
+    field public static final int FLAG_PROFILE = 4096; // 0x1000
+    field public static final int FLAG_QUIET_MODE = 128; // 0x80
+    field @Deprecated public static final int FLAG_RESTRICTED = 8; // 0x8
+    field public static final int FLAG_SYSTEM = 2048; // 0x800
+    field public static final int NO_PROFILE_GROUP_ID = -10000; // 0xffffd8f0
+    field public boolean convertedFromPreCreated;
+    field public long creationTime;
+    field public int flags;
+    field public boolean guestToRemove;
+    field public String iconPath;
+    field public int id;
+    field public String lastLoggedInFingerprint;
+    field public long lastLoggedInTime;
+    field public String name;
+    field public boolean partial;
+    field public boolean preCreated;
+    field public int profileBadge;
+    field public int profileGroupId;
+    field public int restrictedProfileParentId;
+    field public int serialNumber;
+    field public String userType;
+  }
+
 }
 
 package android.content.res {
@@ -845,7 +951,7 @@
 package android.graphics.fonts {
 
   public class FontManager {
-    method @Nullable public android.text.FontConfig getFontConfig();
+    method @NonNull public android.text.FontConfig getFontConfig();
     method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFamily(@NonNull android.graphics.fonts.FontFamilyUpdateRequest, @IntRange(from=0) int);
     method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFile(@NonNull android.graphics.fonts.FontFileUpdateRequest, @IntRange(from=0) int);
     method @Deprecated @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFile(@NonNull android.os.ParcelFileDescriptor, @NonNull byte[], @IntRange(from=0) int);
@@ -866,11 +972,21 @@
 package android.hardware {
 
   public final class SensorPrivacyManager {
-    method public boolean isIndividualSensorPrivacyEnabled(int);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY) public void setIndividualSensorPrivacy(int, boolean);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY) public void setIndividualSensorPrivacyForProfileGroup(int, boolean);
-    field public static final int INDIVIDUAL_SENSOR_CAMERA = 2; // 0x2
-    field public static final int INDIVIDUAL_SENSOR_MICROPHONE = 1; // 0x1
+    method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(int, @NonNull android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener);
+    method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(int, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener);
+    method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public boolean isSensorPrivacyEnabled(int);
+    method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void removeSensorPrivacyListener(@NonNull android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY) public void setSensorPrivacy(int, boolean);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY) public void setSensorPrivacyForProfileGroup(int, boolean);
+  }
+
+  public static interface SensorPrivacyManager.OnSensorPrivacyChangedListener {
+    method public void onSensorPrivacyChanged(boolean);
+  }
+
+  public static class SensorPrivacyManager.Sensors {
+    field public static final int CAMERA = 2; // 0x2
+    field public static final int MICROPHONE = 1; // 0x1
   }
 
 }
@@ -920,17 +1036,19 @@
 package android.hardware.devicestate {
 
   public final class DeviceStateManager {
-    method public void addDeviceStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateListener);
     method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) public void cancelRequest(@NonNull android.hardware.devicestate.DeviceStateRequest);
     method @NonNull public int[] getSupportedStates();
-    method public void removeDeviceStateListener(@NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateListener);
+    method public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateCallback);
     method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) public void requestState(@NonNull android.hardware.devicestate.DeviceStateRequest, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.devicestate.DeviceStateRequest.Callback);
+    method public void unregisterCallback(@NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateCallback);
     field public static final int MAXIMUM_DEVICE_STATE = 255; // 0xff
     field public static final int MINIMUM_DEVICE_STATE = 0; // 0x0
   }
 
-  public static interface DeviceStateManager.DeviceStateListener {
-    method public void onDeviceStateChanged(int);
+  public static interface DeviceStateManager.DeviceStateCallback {
+    method public default void onBaseStateChanged(int);
+    method public void onStateChanged(int);
+    method public default void onSupportedStatesChanged(@NonNull int[]);
   }
 
   public final class DeviceStateRequest {
@@ -1371,6 +1489,7 @@
 
   public abstract class CombinedVibrationEffect implements android.os.Parcelable {
     method public abstract long getDuration();
+    method @NonNull public static android.os.CombinedVibrationEffect.SequentialCombination startSequential();
   }
 
   public static final class CombinedVibrationEffect.Mono extends android.os.CombinedVibrationEffect {
@@ -1388,6 +1507,14 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.os.CombinedVibrationEffect.Sequential> CREATOR;
   }
 
+  public static final class CombinedVibrationEffect.SequentialCombination {
+    method @NonNull public android.os.CombinedVibrationEffect.SequentialCombination addNext(int, @NonNull android.os.VibrationEffect);
+    method @NonNull public android.os.CombinedVibrationEffect.SequentialCombination addNext(int, @NonNull android.os.VibrationEffect, int);
+    method @NonNull public android.os.CombinedVibrationEffect.SequentialCombination addNext(@NonNull android.os.CombinedVibrationEffect);
+    method @NonNull public android.os.CombinedVibrationEffect.SequentialCombination addNext(@NonNull android.os.CombinedVibrationEffect, int);
+    method @NonNull public android.os.CombinedVibrationEffect combine();
+  }
+
   public static final class CombinedVibrationEffect.Stereo extends android.os.CombinedVibrationEffect {
     method public long getDuration();
     method @NonNull public android.util.SparseArray<android.os.VibrationEffect> getEffects();
@@ -1485,8 +1612,15 @@
   }
 
   public class UserManager {
+    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createProfileForUser(@Nullable String, @NonNull String, int, int, @Nullable String[]);
+    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createRestrictedProfile(@Nullable String);
+    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createUser(@Nullable String, @NonNull String, int);
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public String getUserType();
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public java.util.List<android.content.pm.UserInfo> getUsers(boolean, boolean, boolean);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean hasBaseUserRestriction(@NonNull String, @NonNull android.os.UserHandle);
+    method public static boolean isGuestUserEphemeral();
     method public static boolean isSplitSystemUser();
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo preCreateUser(@NonNull String) throws android.os.UserManager.UserOperationException;
   }
 
   public final class VibrationAttributes implements android.os.Parcelable {
@@ -2466,6 +2600,9 @@
 package android.view.contentcapture {
 
   public final class ContentCaptureManager {
+    method @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_CAPTURE) public static void resetTemporaryService(int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_CAPTURE) public static void setDefaultServiceEnabled(int, boolean);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_CAPTURE) public static void setTemporaryService(int, @NonNull String, int);
     field public static final String DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY = "idle_flush_frequency";
     field public static final String DEVICE_CONFIG_PROPERTY_LOGGING_LEVEL = "logging_level";
     field public static final String DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE = "log_history_size";
@@ -2556,10 +2693,6 @@
     method @NonNull public static android.view.inputmethod.InlineSuggestionsResponse newInlineSuggestionsResponse(@NonNull java.util.List<android.view.inputmethod.InlineSuggestion>);
   }
 
-  public final class InputMethodInfo implements android.os.Parcelable {
-    ctor public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, int);
-  }
-
   public final class InputMethodManager {
     method public int getDisplayId();
     method public boolean hasActiveInputConnection(@Nullable android.view.View);
diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt
index 87fb5b1..a536efb 100644
--- a/core/api/test-lint-baseline.txt
+++ b/core/api/test-lint-baseline.txt
@@ -468,7 +468,7 @@
 GetterSetterNames: android.location.GnssMeasurement#setCarrierFrequencyHz(float):
     
 GetterSetterNames: android.location.GnssMeasurement#setCodeType(String):
-
+    
 GetterSetterNames: android.location.GnssMeasurement#setCorrelationVectors(java.util.Collection<android.location.CorrelationVector>):
     
 GetterSetterNames: android.location.GnssMeasurement#setFullInterSignalBiasNanos(double):
@@ -480,7 +480,7 @@
 GetterSetterNames: android.location.GnssMeasurement#setSatelliteInterSignalBiasUncertaintyNanos(double):
     
 GetterSetterNames: android.location.GnssMeasurement#setSatellitePvt(android.location.SatellitePvt):
-
+    
 GetterSetterNames: android.location.GnssMeasurement#setSnrInDb(double):
     
 GetterSetterNames: android.location.LocationRequest#isLocationSettingsIgnored():
@@ -953,6 +953,32 @@
     
 MissingNullability: android.content.pm.ShortcutManager#ShortcutManager(android.content.Context) parameter #0:
     
+MissingNullability: android.content.pm.UserInfo#UserInfo(android.content.pm.UserInfo) parameter #0:
+    Missing nullability on parameter `orig` in method `UserInfo`
+MissingNullability: android.content.pm.UserInfo#UserInfo(int, String, String, int) parameter #1:
+    Missing nullability on parameter `name` in method `UserInfo`
+MissingNullability: android.content.pm.UserInfo#UserInfo(int, String, String, int) parameter #2:
+    Missing nullability on parameter `iconPath` in method `UserInfo`
+MissingNullability: android.content.pm.UserInfo#UserInfo(int, String, String, int, String) parameter #1:
+    Missing nullability on parameter `name` in method `UserInfo`
+MissingNullability: android.content.pm.UserInfo#UserInfo(int, String, String, int, String) parameter #2:
+    Missing nullability on parameter `iconPath` in method `UserInfo`
+MissingNullability: android.content.pm.UserInfo#UserInfo(int, String, String, int, String) parameter #4:
+    Missing nullability on parameter `userType` in method `UserInfo`
+MissingNullability: android.content.pm.UserInfo#UserInfo(int, String, int) parameter #1:
+    Missing nullability on parameter `name` in method `UserInfo`
+MissingNullability: android.content.pm.UserInfo#getUserHandle():
+    Missing nullability on method `getUserHandle` return
+MissingNullability: android.content.pm.UserInfo#iconPath:
+    Missing nullability on field `iconPath` in class `class android.content.pm.UserInfo`
+MissingNullability: android.content.pm.UserInfo#lastLoggedInFingerprint:
+    Missing nullability on field `lastLoggedInFingerprint` in class `class android.content.pm.UserInfo`
+MissingNullability: android.content.pm.UserInfo#name:
+    Missing nullability on field `name` in class `class android.content.pm.UserInfo`
+MissingNullability: android.content.pm.UserInfo#userType:
+    Missing nullability on field `userType` in class `class android.content.pm.UserInfo`
+MissingNullability: android.content.pm.UserInfo#writeToParcel(android.os.Parcel, int) parameter #0:
+    Missing nullability on parameter `dest` in method `writeToParcel`
 MissingNullability: android.content.res.AssetManager#getOverlayablesToString(String) parameter #0:
     
 MissingNullability: android.content.res.Configuration#windowConfiguration:
@@ -2433,6 +2459,38 @@
     
 MutableBareField: android.content.AutofillOptions#whitelistedActivitiesForAugmentedAutofill:
     
+MutableBareField: android.content.pm.UserInfo#convertedFromPreCreated:
+    Bare field convertedFromPreCreated must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#creationTime:
+    Bare field creationTime must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#flags:
+    Bare field flags must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#guestToRemove:
+    Bare field guestToRemove must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#iconPath:
+    Bare field iconPath must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#id:
+    Bare field id must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#lastLoggedInFingerprint:
+    Bare field lastLoggedInFingerprint must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#lastLoggedInTime:
+    Bare field lastLoggedInTime must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#name:
+    Bare field name must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#partial:
+    Bare field partial must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#preCreated:
+    Bare field preCreated must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#profileBadge:
+    Bare field profileBadge must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#profileGroupId:
+    Bare field profileGroupId must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#restrictedProfileParentId:
+    Bare field restrictedProfileParentId must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#serialNumber:
+    Bare field serialNumber must be marked final, or moved behind accessors if mutable
+MutableBareField: android.content.pm.UserInfo#userType:
+    Bare field userType must be marked final, or moved behind accessors if mutable
 MutableBareField: android.database.sqlite.SQLiteDebug.DbStats#cache:
     
 MutableBareField: android.database.sqlite.SQLiteDebug.DbStats#dbName:
@@ -2548,15 +2606,15 @@
 NoSettingsProvider: android.provider.Settings.Global#USE_OPEN_WIFI_PACKAGE:
     
 NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED:
-
+    
 NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_CAPABILITY:
-
+    
 NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE:
-
+    
 NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_ALL:
-
+    
 NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN:
-
+    
 NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW:
     
 NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_SHORTCUT_TARGET_SERVICE:
@@ -2619,6 +2677,10 @@
     
 
 
+NullableCollection: android.os.UserManager#createProfileForUser(String, String, int, int, String[]) parameter #4:
+    Type of parameter disallowedPackages in android.os.UserManager.createProfileForUser(String name, String userType, int flags, int userId, String[] disallowedPackages) is a nullable collection (`java.lang.String[]`); must be non-null
+
+
 OnNameExpected: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.PrintWriter, String[]):
     
 OnNameExpected: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
@@ -2729,6 +2791,8 @@
 
 ParcelNotFinal: android.app.WindowConfiguration:
     
+ParcelNotFinal: android.content.pm.UserInfo:
+    Parcelable classes must be final: android.content.pm.UserInfo is not final
 ParcelNotFinal: android.net.metrics.IpConnectivityLog.Event:
     
 ParcelNotFinal: android.os.IncidentManager.IncidentReport:
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a73fe71..f5f0b42 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -803,6 +803,7 @@
     @UnsupportedAppUsage
     private IBinder mToken;
     private IBinder mAssistToken;
+    private IBinder mShareableActivityToken;
     @UnsupportedAppUsage
     private int mIdent;
     @UnsupportedAppUsage
@@ -1210,7 +1211,7 @@
                     if (window != null) {
                         cm.updateWindowAttributes(window.getAttributes());
                     }
-                    cm.onActivityCreated(mToken, getComponentName());
+                    cm.onActivityCreated(mToken, mShareableActivityToken, getComponentName());
                     break;
                 case CONTENT_CAPTURE_RESUME:
                     cm.onActivityResumed();
@@ -7118,6 +7119,9 @@
                 case "--contentcapture":
                     dumpContentCaptureManager(prefix, writer);
                     return;
+                case "--translation":
+                    dumpUiTranslation(prefix, writer);
+                    return;
             }
         }
         writer.print(prefix); writer.print("Local Activity ");
@@ -7158,6 +7162,7 @@
 
         dumpAutofillManager(prefix, writer);
         dumpContentCaptureManager(prefix, writer);
+        dumpUiTranslation(prefix, writer);
 
         ResourcesManager.getInstance().dump(prefix, writer);
     }
@@ -7182,6 +7187,14 @@
         }
     }
 
+    void dumpUiTranslation(String prefix, PrintWriter writer) {
+        if (mUiTranslationController != null) {
+            mUiTranslationController.dump(prefix, writer);
+        } else {
+            writer.print(prefix); writer.println("No UiTranslationController");
+        }
+    }
+
     /**
      * Bit indicating that this activity is "immersive" and should not be
      * interrupted by notifications if possible.
@@ -7838,7 +7851,8 @@
             CharSequence title, Activity parent, String id,
             NonConfigurationInstances lastNonConfigurationInstances,
             Configuration config, String referrer, IVoiceInteractor voiceInteractor,
-            Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
+            Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken,
+            IBinder shareableActivityToken) {
         attachBaseContext(context);
 
         mFragments.attachHost(null /*parent*/);
@@ -7860,6 +7874,7 @@
         mInstrumentation = instr;
         mToken = token;
         mAssistToken = assistToken;
+        mShareableActivityToken = shareableActivityToken;
         mIdent = ident;
         mApplication = application;
         mIntent = intent;
@@ -7918,6 +7933,11 @@
     }
 
     /** @hide */
+    public final IBinder getShareableActivityToken() {
+        return mParent != null ? mParent.getShareableActivityToken() : mShareableActivityToken;
+    }
+
+    /** @hide */
     @VisibleForTesting
     public final ActivityThread getActivityThread() {
         return mMainThread;
diff --git a/core/java/android/app/ActivityManager.aidl b/core/java/android/app/ActivityManager.aidl
index 341393c..eb7cac07 100644
--- a/core/java/android/app/ActivityManager.aidl
+++ b/core/java/android/app/ActivityManager.aidl
@@ -17,6 +17,7 @@
 package android.app;
 
 parcelable ActivityManager.MemoryInfo;
+parcelable ActivityManager.PendingIntentInfo;
 parcelable ActivityManager.ProcessErrorStateInfo;
 parcelable ActivityManager.RecentTaskInfo;
 parcelable ActivityManager.TaskDescription;
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 220c332..f905ec8 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -511,6 +511,7 @@
     /** @hide Process is hosting the current top activities.  Note that this covers
      * all activities that are visible to the user. */
     @UnsupportedAppUsage
+    @TestApi
     public static final int PROCESS_STATE_TOP = ProcessStateEnum.TOP;
 
     /** @hide Process is bound to a TOP app. */
@@ -518,6 +519,7 @@
 
     /** @hide Process is hosting a foreground service. */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    @TestApi
     public static final int PROCESS_STATE_FOREGROUND_SERVICE = ProcessStateEnum.FOREGROUND_SERVICE;
 
     /** @hide Process is hosting a foreground service due to a system binding. */
@@ -617,6 +619,7 @@
     public static final int PROCESS_CAPABILITY_FOREGROUND_MICROPHONE = 1 << 2;
 
     /** @hide Process can access network despite any power saving resrictions */
+    @TestApi
     public static final int PROCESS_CAPABILITY_NETWORK = 1 << 3;
 
     /** @hide all capabilities, the ORing of all flags in {@link ProcessCapability}*/
@@ -3432,6 +3435,36 @@
     }
 
     /**
+     * Returns the process state of this uid.
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(Manifest.permission.PACKAGE_USAGE_STATS)
+    public int getUidProcessState(int uid) {
+        try {
+            return getService().getUidProcessState(uid, mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns the process capability of this uid.
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(Manifest.permission.PACKAGE_USAGE_STATS)
+    public @ProcessCapability int getUidProcessCapabilities(int uid) {
+        try {
+            return getService().getUidProcessCapabilities(uid, mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Return the importance of a given package name, based on the processes that are
      * currently running.  The return value is one of the importance constants defined
      * in {@link RunningAppProcessInfo}, giving you the highest importance of all the
@@ -4776,4 +4809,71 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * A subset of immutable pending intent information suitable for caching on the client side.
+     *
+     * @hide
+     */
+    public static final class PendingIntentInfo implements Parcelable {
+
+        private final String mCreatorPackage;
+        private final int mCreatorUid;
+        private final boolean mImmutable;
+        private final int mIntentSenderType;
+
+        public PendingIntentInfo(String creatorPackage, int creatorUid, boolean immutable,
+                int intentSenderType) {
+            mCreatorPackage = creatorPackage;
+            mCreatorUid = creatorUid;
+            mImmutable = immutable;
+            mIntentSenderType = intentSenderType;
+        }
+
+        public String getCreatorPackage() {
+            return mCreatorPackage;
+        }
+
+        public int getCreatorUid() {
+            return mCreatorUid;
+        }
+
+        public boolean isImmutable() {
+            return mImmutable;
+        }
+
+        public int getIntentSenderType() {
+            return mIntentSenderType;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(@NonNull Parcel parcel, int flags) {
+            parcel.writeString(mCreatorPackage);
+            parcel.writeInt(mCreatorUid);
+            parcel.writeBoolean(mImmutable);
+            parcel.writeInt(mIntentSenderType);
+        }
+
+        public static final @NonNull Creator<PendingIntentInfo> CREATOR =
+                new Creator<PendingIntentInfo>() {
+                    @Override
+                    public PendingIntentInfo createFromParcel(Parcel in) {
+                        return new PendingIntentInfo(
+                                /* creatorPackage= */ in.readString(),
+                                /* creatorUid= */ in.readInt(),
+                                /* immutable= */ in.readBoolean(),
+                                /* intentSenderType= */ in.readInt());
+                    }
+
+                    @Override
+                    public PendingIntentInfo[] newArray(int size) {
+                        return new PendingIntentInfo[size];
+                    }
+                };
+    }
 }
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index c31c22c..c812e8e 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -30,6 +30,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.PowerWhitelistManager.ReasonCode;
 import android.os.PowerWhitelistManager.TempAllowListType;
 import android.os.TransactionTooLargeException;
 import android.os.WorkSource;
@@ -102,12 +103,15 @@
      * Sets how long a {@link PendingIntent} can be temporarily allowlisted to bypass restrictions
      * such as Power Save mode.
      * @param target
-     * @param whitelistToken
+     * @param allowlistToken
      * @param duration temp allowlist duration in milliseconds.
      * @param type temp allowlist type defined at {@link TempAllowListType}
+     * @param reasonCode one of {@link ReasonCode}
+     * @param reason A human-readable reason for logging purposes.
      */
-    public abstract void setPendingIntentWhitelistDuration(IIntentSender target,
-            IBinder whitelistToken, long duration, int type);
+    public abstract void setPendingIntentAllowlistDuration(IIntentSender target,
+            IBinder allowlistToken, long duration, @TempAllowListType int type,
+            @ReasonCode int reasonCode, @Nullable String reason);
 
     /**
      * Returns the flags set for a {@link PendingIntent}.
@@ -127,20 +131,26 @@
             IBinder allowlistToken);
 
     /**
-     * Allow DeviceIdleController to tell us about what apps are whitelisted.
+     * Allow DeviceIdleController to tell us about what apps are allowlisted.
      */
-    public abstract void setDeviceIdleWhitelist(int[] allAppids, int[] exceptIdleAppids);
+    public abstract void setDeviceIdleAllowlist(int[] allAppids, int[] exceptIdleAppids);
 
     /**
-     * Update information about which app IDs are on the temp whitelist.
+     * Update information about which app IDs are on the temp allowlist.
      * @param appids the updated list of appIds in temp allowlist.
      * @param changingUid uid to add or remove to temp allowlist.
      * @param adding true to add to temp allowlist, false to remove from temp allowlist.
      * @param durationMs when adding is true, the duration to be in temp allowlist.
      * @param type temp allowlist type defined at {@link TempAllowListType}.
+     * @param reasonCode one of {@link ReasonCode}
+     * @param reason A human-readable reason for logging purposes.
+     * @param callingUid the callingUid that setup this temp allowlist, only valid when param adding
+     *                   is true.
      */
-    public abstract void updateDeviceIdleTempWhitelist(int[] appids, int changingUid,
-            boolean adding, long durationMs, @TempAllowListType int type);
+    public abstract void updateDeviceIdleTempAllowlist(int[] appids, int changingUid,
+            boolean adding, long durationMs, @TempAllowListType int type,
+            @ReasonCode int reasonCode,
+            @Nullable String reason, int callingUid);
 
     /**
      * Get the procstate for the UID.  The return value will be between
@@ -335,10 +345,11 @@
      * @param targetUid the UID that is been temp allowlisted.
      * @param duration temp allowlist duration in milliseconds.
      * @param type temp allowlist type defined at {@link TempAllowListType}
-     * @param tag
+     * @param reasonCode one of {@link ReasonCode}
+     * @param reason
      */
-    public abstract void tempWhitelistForPendingIntent(int callerPid, int callerUid, int targetUid,
-            long duration, int type, String tag);
+    public abstract void tempAllowlistForPendingIntent(int callerPid, int callerUid, int targetUid,
+            long duration, int type, @ReasonCode int reasonCode, String reason);
 
     public abstract int broadcastIntentInPackage(String packageName, @Nullable String featureId,
             int uid, int realCallingUid, int realCallingPid, Intent intent, String resolvedType,
@@ -495,9 +506,9 @@
 
     /**
      * Sends a broadcast, assuming the caller to be the system and allowing the inclusion of an
-     * approved whitelist of app Ids >= {@link android.os.Process#FIRST_APPLICATION_UID} that the
+     * approved allowlist of app Ids >= {@link android.os.Process#FIRST_APPLICATION_UID} that the
      * broadcast my be sent to; any app Ids < {@link android.os.Process#FIRST_APPLICATION_UID} are
-     * automatically whitelisted.
+     * automatically allowlisted.
      *
      * @see com.android.server.am.ActivityManagerService#broadcastIntentWithFeature(
      *      IApplicationThread, String, Intent, String, IIntentReceiver, int, String, Bundle,
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 73cc13c8..a1dce77 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -320,6 +320,10 @@
     private static final String KEY_OVERRIDE_TASK_TRANSITION =
             "android:activity.overrideTaskTransition";
 
+    /** See {@link #setRemoveWithTaskOrganizer(boolean)}. */
+    private static final String KEY_REMOVE_WITH_TASK_ORGANIZER =
+            "android.activity.removeWithTaskOrganizer";
+
     /**
      * @see #setLaunchCookie
      * @hide
@@ -405,6 +409,7 @@
     private IRemoteTransition mRemoteTransition;
     private boolean mOverrideTaskTransition;
     private int mSplashScreenThemeResId;
+    private boolean mRemoveWithTaskOrganizer;
 
     /**
      * Create an ActivityOptions specifying a custom animation to run when
@@ -1155,6 +1160,7 @@
                 KEY_REMOTE_TRANSITION));
         mOverrideTaskTransition = opts.getBoolean(KEY_OVERRIDE_TASK_TRANSITION);
         mSplashScreenThemeResId = opts.getInt(KEY_SPLASH_SCREEN_THEME);
+        mRemoveWithTaskOrganizer = opts.getBoolean(KEY_REMOVE_WITH_TASK_ORGANIZER);
     }
 
     /**
@@ -1624,6 +1630,22 @@
     }
 
     /**
+     * Sets whether to remove the task when TaskOrganizer, which is managing it, is destroyed.
+     * @hide
+     */
+    public void setRemoveWithTaskOrganizer(boolean remove) {
+        mRemoveWithTaskOrganizer = remove;
+    }
+
+    /**
+     * @return whether to remove the task when TaskOrganizer, which is managing it, is destroyed.
+     * @hide
+     */
+    public boolean getRemoveWithTaskOranizer() {
+        return mRemoveWithTaskOrganizer;
+    }
+
+    /**
      * Update the current values in this ActivityOptions from those supplied
      * in <var>otherOptions</var>.  Any values
      * defined in <var>otherOptions</var> replace those in the base options.
@@ -1857,6 +1879,9 @@
         if (mSplashScreenThemeResId != 0) {
             b.putInt(KEY_SPLASH_SCREEN_THEME, mSplashScreenThemeResId);
         }
+        if (mRemoveWithTaskOrganizer) {
+            b.putBoolean(KEY_REMOVE_WITH_TASK_ORGANIZER, mRemoveWithTaskOrganizer);
+        }
         return b;
     }
 
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 47d2e7c..730fce9 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -517,6 +517,9 @@
         @UnsupportedAppUsage
         public IBinder token;
         public IBinder assistToken;
+        // A reusable token for other purposes, e.g. content capture, translation. It shouldn't be
+        // used without security checks
+        public IBinder shareableActivityToken;
         int ident;
         @UnsupportedAppUsage
         Intent intent;
@@ -604,9 +607,11 @@
                 PersistableBundle persistentState, List<ResultInfo> pendingResults,
                 List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions,
                 boolean isForward, ProfilerInfo profilerInfo, ClientTransactionHandler client,
-                IBinder assistToken, FixedRotationAdjustments fixedRotationAdjustments) {
+                IBinder assistToken, FixedRotationAdjustments fixedRotationAdjustments,
+                IBinder shareableActivityToken) {
             this.token = token;
             this.assistToken = assistToken;
+            this.shareableActivityToken = shareableActivityToken;
             this.ident = ident;
             this.intent = intent;
             this.referrer = referrer;
@@ -3157,11 +3162,13 @@
 
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public final Activity startActivityNow(Activity parent, String id,
-        Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state,
-        Activity.NonConfigurationInstances lastNonConfigurationInstances, IBinder assistToken) {
+            Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state,
+            Activity.NonConfigurationInstances lastNonConfigurationInstances, IBinder assistToken,
+            IBinder shareableActivityToken) {
         ActivityClientRecord r = new ActivityClientRecord();
             r.token = token;
             r.assistToken = assistToken;
+            r.shareableActivityToken = shareableActivityToken;
             r.ident = 0;
             r.intent = intent;
             r.state = state;
@@ -3504,7 +3511,7 @@
                         r.ident, app, r.intent, r.activityInfo, title, r.parent,
                         r.embeddedID, r.lastNonConfigurationInstances, config,
                         r.referrer, r.voiceInteractor, window, r.configCallback,
-                        r.assistToken);
+                        r.assistToken, r.shareableActivityToken);
 
                 if (customIntent != null) {
                     activity.mIntent = customIntent;
diff --git a/core/java/android/app/AnrController.java b/core/java/android/app/AnrController.java
index cfc9d27..a0d4b3a 100644
--- a/core/java/android/app/AnrController.java
+++ b/core/java/android/app/AnrController.java
@@ -23,7 +23,29 @@
 public interface AnrController {
     /**
      * Returns the delay in milliseconds for an ANR dialog that is about to be shown for
-     * {@code packageName}.
+     * {@code packageName} with {@code uid}.
+     *
+     * Implementations should only return a positive value if they actually expect the
+     * {@code packageName} to be delayed due to them.
+
+     * If there are multiple controllers registered, the controller with the max delay will
+     * be selected and will receive an {@link #onAnrDelayStarted} callback at the start of the
+     * delay and an {@link #onAnrDelayCompleted} at the end of the delay.
      */
     long getAnrDelayMillis(String packageName, int uid);
+
+    /**
+     * Notifies the controller at the start of the ANR dialog delay for {@code packageName} with
+     * {@code uid}. The controller can decide to show a progress UI after this notification.
+     */
+    void onAnrDelayStarted(String packageName, int uid);
+
+    /**
+     * Notifies the controller at the end of the ANR dialog delay for {@code packageName} with
+     * {@code uid}.
+     *
+     * @return whether the ANR dialog should be shown or cancelled. {@code true} if the
+     * ANR dialog should be shown, {@code false} if it should be cancelled.
+     */
+    boolean onAnrDelayCompleted(String packageName, int uid);
 }
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 2f3b50b..dd1bc7c 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import static java.lang.Long.max;
+
 import android.Manifest;
 import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
@@ -1141,23 +1143,20 @@
      *
      * @hide
      */
-    // TODO: Add as AppProtoEnums
-    public static final int OP_PHONE_CALL_MICROPHONE = 100;
+    public static final int OP_PHONE_CALL_MICROPHONE = AppProtoEnums.APP_OP_PHONE_CALL_MICROPHONE;
     /**
      * Phone call is using camera
      *
      * @hide
      */
-    // TODO: Add as AppProtoEnums
-    public static final int OP_PHONE_CALL_CAMERA = 101;
+    public static final int OP_PHONE_CALL_CAMERA = AppProtoEnums.APP_OP_PHONE_CALL_CAMERA;
 
     /**
      * Audio is being recorded for hotword detection.
      *
      * @hide
      */
-    // TODO: Add as AppProtoEnums
-    public static final int OP_RECORD_AUDIO_HOTWORD = 102;
+    public static final int OP_RECORD_AUDIO_HOTWORD = AppProtoEnums.APP_OP_RECORD_AUDIO_HOTWORD;
 
     /**
      * Manage credentials in the system KeyChain.
@@ -1184,10 +1183,29 @@
      */
     public static final int OP_SCHEDULE_EXACT_ALARM = AppProtoEnums.APP_OP_SCHEDULE_EXACT_ALARM;
 
+    /**
+     * Fine location being accessed by a location source, which is
+     * a component that already has location data since it is the one
+     * that produces location, which is it is a data source for
+     * location data.
+     *
+     * @hide
+     */
+    public static final int OP_FINE_LOCATION_SOURCE = AppProtoEnums.APP_OP_FINE_LOCATION_SOURCE;
+
+    /**
+     * Coarse location being accessed by a location source, which is
+     * a component that already has location data since it is the one
+     * that produces location, which is it is a data source for
+     * location data.
+     *
+     * @hide
+     */
+    public static final int OP_COARSE_LOCATION_SOURCE = AppProtoEnums.APP_OP_COARSE_LOCATION_SOURCE;
 
     /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public static final int _NUM_OP = 108;
+    public static final int _NUM_OP = 110;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1567,6 +1585,24 @@
      */
     public static final String OPSTR_SCHEDULE_EXACT_ALARM = "android:schedule_exact_alarm";
 
+    /**
+     * Fine location being accessed by a location source, which is
+     * a component that already has location since it is the one that
+     * produces location.
+     *
+     * @hide
+     */
+    public static final String OPSTR_FINE_LOCATION_SOURCE = "android:fine_location_source";
+
+    /**
+     * Coarse location being accessed by a location source, which is
+     * a component that already has location since it is the one that
+     * produces location.
+     *
+     * @hide
+     */
+    public static final String OPSTR_COARSE_LOCATION_SOURCE = "android:coarse_location_source";
+
     /** {@link #sAppOpsToNote} not initialized yet for this op */
     private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
     /** Should not collect noting of this app-op in {@link #sAppOpsToNote} */
@@ -1767,6 +1803,8 @@
             OP_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER, // USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER
             OP_RECORD_AUDIO_OUTPUT,             // RECORD_AUDIO_OUTPUT
             OP_SCHEDULE_EXACT_ALARM,            // SCHEDULE_EXACT_ALARM
+            OP_FINE_LOCATION,                   // OP_FINE_LOCATION_SOURCE
+            OP_COARSE_LOCATION,                 // OP_COARSE_LOCATION_SOURCE
     };
 
     /**
@@ -1881,6 +1919,8 @@
             OPSTR_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER,
             OPSTR_RECORD_AUDIO_OUTPUT,
             OPSTR_SCHEDULE_EXACT_ALARM,
+            OPSTR_FINE_LOCATION_SOURCE,
+            OPSTR_COARSE_LOCATION_SOURCE,
     };
 
     /**
@@ -1996,6 +2036,8 @@
             "USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER",
             "RECORD_AUDIO_OUTPUT",
             "SCHEDULE_EXACT_ALARM",
+            "FINE_LOCATION_SOURCE",
+            "COARSE_LOCATION_SOURCE",
     };
 
     /**
@@ -2112,6 +2154,8 @@
             Manifest.permission.USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER,
             null, // no permission for OP_RECORD_AUDIO_OUTPUT
             Manifest.permission.SCHEDULE_EXACT_ALARM,
+            null, // no permission for OP_ACCESS_FINE_LOCATION_SOURCE,
+            null, // no permission for OP_ACCESS_COARSE_LOCATION_SOURCE,
     };
 
     /**
@@ -2228,6 +2272,8 @@
             null, // USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER
             null, // RECORD_AUDIO_OUTPUT
             null, // SCHEDULE_EXACT_ALARM
+            null, // ACCESS_FINE_LOCATION_SOURCE
+            null, // ACCESS_COARSE_LOCATION_SOURCE
     };
 
     /**
@@ -2343,6 +2389,8 @@
             null, // USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER
             null, // RECORD_AUDIO_OUTPUT
             null, // SCHEDULE_EXACT_ALARM
+            null, // ACCESS_FINE_LOCATION_SOURCE
+            null, // ACCESS_COARSE_LOCATION_SOURCE
     };
 
     /**
@@ -2457,6 +2505,8 @@
             AppOpsManager.MODE_DEFAULT, // USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER
             AppOpsManager.MODE_ALLOWED, // RECORD_AUDIO_OUTPUT
             AppOpsManager.MODE_DEFAULT, // SCHEDULE_EXACT_ALARM
+            AppOpsManager.MODE_ALLOWED, // ACCESS_FINE_LOCATION_SOURCE
+            AppOpsManager.MODE_ALLOWED, // ACCESS_COARSE_LOCATION_SOURCE
     };
 
     /**
@@ -2575,6 +2625,8 @@
             true, // USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER
             false, // RECORD_AUDIO_OUTPUT
             false, // SCHEDULE_EXACT_ALARM
+            false, // ACCESS_FINE_LOCATION_SOURCE
+            false, // ACCESS_COARSE_LOCATION_SOURCE
     };
 
     /**
@@ -3335,6 +3387,13 @@
         @DataClass.ParcelWith(LongSparseArrayParceling.class)
         private final @Nullable LongSparseArray<NoteOpEvent> mRejectEvents;
 
+        private AttributedOpEntry(@NonNull AttributedOpEntry other) {
+            mOp = other.mOp;
+            mRunning = other.mRunning;
+            mAccessEvents = other.mAccessEvents == null ? null : other.mAccessEvents.clone();
+            mRejectEvents = other.mRejectEvents == null ? null : other.mRejectEvents.clone();
+        }
+
         /**
          * Returns all keys for which we have events.
          *
@@ -3699,6 +3758,15 @@
             return lastEvent.getProxy();
         }
 
+        @NonNull
+        String getOpName() {
+            return AppOpsManager.opToPublicName(mOp);
+        }
+
+        int getOp() {
+            return mOp;
+        }
+
         private static class LongSparseArrayParceling implements
                 Parcelling<LongSparseArray<NoteOpEvent>> {
             @Override
@@ -4521,6 +4589,50 @@
     }
 
     /**
+     * Flag for querying app op history: get only aggregate information and no
+     * discrete accesses.
+     *
+     * @see #getHistoricalOps(HistoricalOpsRequest, Executor, Consumer)
+     *
+     * @hide
+     */
+    @TestApi
+    @SystemApi
+    public static final int HISTORY_FLAG_AGGREGATE = 1 << 0;
+
+    /**
+     * Flag for querying app op history: get only discrete information and no
+     * aggregate accesses.
+     *
+     * @see #getHistoricalOps(HistoricalOpsRequest, Executor, Consumer)
+     *
+     * @hide
+     */
+    @TestApi
+    @SystemApi
+    public static final int HISTORY_FLAG_DISCRETE = 1 << 1;
+
+    /**
+     * Flag for querying app op history: get all types of historical accesses.
+     *
+     * @see #getHistoricalOps(HistoricalOpsRequest, Executor, Consumer)
+     *
+     * @hide
+     */
+    @TestApi
+    @SystemApi
+    public static final int HISTORY_FLAGS_ALL = HISTORY_FLAG_AGGREGATE
+            | HISTORY_FLAG_DISCRETE;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, prefix = { "HISTORY_FLAG_" }, value = {
+            HISTORY_FLAG_AGGREGATE,
+            HISTORY_FLAG_DISCRETE
+    })
+    public @interface OpHistoryFlags {}
+
+    /**
      * Specifies what parameters to filter historical appop requests for
      *
      * @hide
@@ -4575,6 +4687,7 @@
         private final @Nullable String mPackageName;
         private final @Nullable String mAttributionTag;
         private final @Nullable List<String> mOpNames;
+        private final @OpHistoryFlags int mHistoryFlags;
         private final @HistoricalOpsRequestFilter int mFilter;
         private final long mBeginTimeMillis;
         private final long mEndTimeMillis;
@@ -4582,12 +4695,13 @@
 
         private HistoricalOpsRequest(int uid, @Nullable String packageName,
                 @Nullable String attributionTag, @Nullable List<String> opNames,
-                @HistoricalOpsRequestFilter int filter, long beginTimeMillis,
-                long endTimeMillis, @OpFlags int flags) {
+                @OpHistoryFlags int historyFlags, @HistoricalOpsRequestFilter int filter,
+                long beginTimeMillis, long endTimeMillis, @OpFlags int flags) {
             mUid = uid;
             mPackageName = packageName;
             mAttributionTag = attributionTag;
             mOpNames = opNames;
+            mHistoryFlags = historyFlags;
             mFilter = filter;
             mBeginTimeMillis = beginTimeMillis;
             mEndTimeMillis = endTimeMillis;
@@ -4605,6 +4719,7 @@
             private @Nullable String mPackageName;
             private @Nullable String mAttributionTag;
             private @Nullable List<String> mOpNames;
+            private @OpHistoryFlags int mHistoryFlags;
             private @HistoricalOpsRequestFilter int mFilter;
             private final long mBeginTimeMillis;
             private final long mEndTimeMillis;
@@ -4626,6 +4741,7 @@
                         "beginTimeMillis must be non negative and lesser than endTimeMillis");
                 mBeginTimeMillis = beginTimeMillis;
                 mEndTimeMillis = endTimeMillis;
+                mHistoryFlags = HISTORY_FLAG_AGGREGATE;
             }
 
             /**
@@ -4722,11 +4838,25 @@
             }
 
             /**
+             * Specifies what type of historical information to query.
+             *
+             * @param flags Flags for the historical types to fetch which are any
+             * combination of {@link #HISTORY_FLAG_AGGREGATE}, {@link #HISTORY_FLAG_DISCRETE},
+             * {@link #HISTORY_FLAGS_ALL}. The default is {@link #HISTORY_FLAG_AGGREGATE}.
+             * @return This builder.
+             */
+            public @NonNull Builder setHistoryFlags(@OpHistoryFlags int flags) {
+                Preconditions.checkFlagsArgument(flags, HISTORY_FLAGS_ALL);
+                mHistoryFlags = flags;
+                return this;
+            }
+
+            /**
              * @return a new {@link HistoricalOpsRequest}.
              */
             public @NonNull HistoricalOpsRequest build() {
                 return new HistoricalOpsRequest(mUid, mPackageName, mAttributionTag, mOpNames,
-                        mFilter, mBeginTimeMillis, mEndTimeMillis, mFlags);
+                        mHistoryFlags, mFilter, mBeginTimeMillis, mEndTimeMillis, mFlags);
             }
         }
     }
@@ -4893,7 +5023,8 @@
          * @hide
          */
         public void filter(int uid, @Nullable String packageName, @Nullable String attributionTag,
-                @Nullable String[] opNames, @HistoricalOpsRequestFilter int filter,
+                @Nullable String[] opNames, @OpHistoryFlags int historyFilter,
+                @HistoricalOpsRequestFilter int filter,
                 long beginTimeMillis, long endTimeMillis) {
             final long durationMillis = getDurationMillis();
             mBeginTimeMillis = Math.max(mBeginTimeMillis, beginTimeMillis);
@@ -4906,7 +5037,8 @@
                 if ((filter & FILTER_BY_UID) != 0 && uid != uidOp.getUid()) {
                     mHistoricalUidOps.removeAt(i);
                 } else {
-                    uidOp.filter(packageName, attributionTag, opNames, filter, scaleFactor);
+                    uidOp.filter(packageName, attributionTag, opNames, filter, historyFilter,
+                            scaleFactor, mBeginTimeMillis, mEndTimeMillis);
                     if (uidOp.getPackageCount() == 0) {
                         mHistoricalUidOps.removeAt(i);
                     }
@@ -4963,6 +5095,16 @@
 
         /** @hide */
         @TestApi
+        public void addDiscreteAccess(int opCode, int uid, @NonNull String packageName,
+                @Nullable String attributionTag, @UidState int uidState, @OpFlags int opFlag,
+                long discreteAccessTime, long discreteAccessDuration) {
+            getOrCreateHistoricalUidOps(uid).addDiscreteAccess(opCode, packageName, attributionTag,
+                    uidState, opFlag, discreteAccessTime, discreteAccessDuration);
+        };
+
+
+        /** @hide */
+        @TestApi
         public void offsetBeginAndEndTime(long offsetMillis) {
             mBeginTimeMillis += offsetMillis;
             mEndTimeMillis += offsetMillis;
@@ -5238,7 +5380,8 @@
 
         private void filter(@Nullable String packageName, @Nullable String attributionTag,
                 @Nullable String[] opNames, @HistoricalOpsRequestFilter int filter,
-                double fractionToRemove) {
+                @OpHistoryFlags int historyFilter, double fractionToRemove, long beginTimeMillis,
+                long endTimeMillis) {
             final int packageCount = getPackageCount();
             for (int i = packageCount - 1; i >= 0; i--) {
                 final HistoricalPackageOps packageOps = getPackageOpsAt(i);
@@ -5246,7 +5389,8 @@
                         packageOps.getPackageName())) {
                     mHistoricalPackageOps.removeAt(i);
                 } else {
-                    packageOps.filter(attributionTag, opNames, filter, fractionToRemove);
+                    packageOps.filter(attributionTag, opNames, filter, historyFilter,
+                            fractionToRemove, beginTimeMillis, endTimeMillis);
                     if (packageOps.getAttributedOpsCount() == 0) {
                         mHistoricalPackageOps.removeAt(i);
                     }
@@ -5286,6 +5430,13 @@
                     opCode, attributionTag, uidState, flags, increment);
         }
 
+        private void addDiscreteAccess(int opCode, @NonNull String packageName,
+                @Nullable String attributionTag, @UidState int uidState,
+                @OpFlags int flag, long discreteAccessTime, long discreteAccessDuration) {
+            getOrCreateHistoricalPackageOps(packageName).addDiscreteAccess(opCode, attributionTag,
+                    uidState, flag, discreteAccessTime, discreteAccessDuration);
+        };
+
         /**
          * @return The UID for which the data is related.
          */
@@ -5490,7 +5641,8 @@
         }
 
         private void filter(@Nullable String attributionTag, @Nullable String[] opNames,
-                @HistoricalOpsRequestFilter int filter, double fractionToRemove) {
+                @HistoricalOpsRequestFilter int filter, @OpHistoryFlags int historyFilter,
+                double fractionToRemove, long beginTimeMillis, long endTimeMillis) {
             final int attributionCount = getAttributedOpsCount();
             for (int i = attributionCount - 1; i >= 0; i--) {
                 final AttributedHistoricalOps attributionOps = getAttributedOpsAt(i);
@@ -5498,7 +5650,8 @@
                         attributionOps.getTag())) {
                     mAttributedHistoricalOps.removeAt(i);
                 } else {
-                    attributionOps.filter(opNames, filter, fractionToRemove);
+                    attributionOps.filter(opNames, filter, historyFilter, fractionToRemove,
+                            beginTimeMillis, endTimeMillis);
                     if (attributionOps.getOpCount() == 0) {
                         mAttributedHistoricalOps.removeAt(i);
                     }
@@ -5543,6 +5696,13 @@
                     opCode, uidState, flags, increment);
         }
 
+        private void addDiscreteAccess(int opCode, @Nullable String attributionTag,
+                @UidState int uidState, @OpFlags int flag, long discreteAccessTime,
+                long discreteAccessDuration) {
+            getOrCreateAttributedHistoricalOps(attributionTag).addDiscreteAccess(opCode, uidState,
+                    flag, discreteAccessTime, discreteAccessDuration);
+        }
+
         /**
          * Gets the package name which the data represents.
          *
@@ -5820,7 +5980,8 @@
         }
 
         private void filter(@Nullable String[] opNames, @HistoricalOpsRequestFilter int filter,
-                double scaleFactor) {
+                @OpHistoryFlags int historyFilter, double scaleFactor, long beginTimeMillis,
+                long endTimeMillis) {
             final int opCount = getOpCount();
             for (int i = opCount - 1; i >= 0; i--) {
                 final HistoricalOp op = mHistoricalOps.valueAt(i);
@@ -5828,7 +5989,7 @@
                         op.getOpName())) {
                     mHistoricalOps.removeAt(i);
                 } else {
-                    op.filter(scaleFactor);
+                    op.filter(historyFilter, scaleFactor, beginTimeMillis, endTimeMillis);
                 }
             }
         }
@@ -5859,6 +6020,12 @@
             getOrCreateHistoricalOp(opCode).increaseAccessDuration(uidState, flags, increment);
         }
 
+        private void addDiscreteAccess(int opCode, @UidState int uidState, @OpFlags int flag,
+                long discreteAccessTime, long discreteAccessDuration) {
+            getOrCreateHistoricalOp(opCode).addDiscreteAccess(uidState,flag, discreteAccessTime,
+                    discreteAccessDuration);
+        }
+
         /**
          * Gets number historical app ops.
          *
@@ -5920,8 +6087,6 @@
             return op;
         }
 
-
-
         // Code below generated by codegen v1.0.14.
         //
         // DO NOT MODIFY!
@@ -6071,6 +6236,9 @@
         private @Nullable LongSparseLongArray mRejectCount;
         private @Nullable LongSparseLongArray mAccessDuration;
 
+        /** Discrete Ops for this Op */
+        private @Nullable List<AttributedOpEntry> mDiscreteAccesses;
+
         /** @hide */
         public HistoricalOp(int op) {
             mOp = op;
@@ -6087,6 +6255,12 @@
             if (other.mAccessDuration != null) {
                 mAccessDuration = other.mAccessDuration.clone();
             }
+            final int historicalOpCount = other.getDiscreteAccessCount();
+            for (int i = 0; i < historicalOpCount; i++) {
+                final AttributedOpEntry origOp = other.getDiscreteAccessAt(i);
+                final AttributedOpEntry cloneOp = new AttributedOpEntry(origOp);
+                getOrCreateDiscreteAccesses().add(cloneOp);
+            }
         }
 
         private HistoricalOp(@NonNull Parcel parcel) {
@@ -6094,22 +6268,45 @@
             mAccessCount = readLongSparseLongArrayFromParcel(parcel);
             mRejectCount = readLongSparseLongArrayFromParcel(parcel);
             mAccessDuration = readLongSparseLongArrayFromParcel(parcel);
+            mDiscreteAccesses = readDiscreteAccessArrayFromParcel(parcel);
         }
 
-        private void filter(double scaleFactor) {
-            scale(mAccessCount, scaleFactor);
-            scale(mRejectCount, scaleFactor);
-            scale(mAccessDuration, scaleFactor);
+        private void filter(@OpHistoryFlags int historyFlag, double scaleFactor,
+                long beginTimeMillis, long endTimeMillis) {
+            if ((historyFlag & HISTORY_FLAG_AGGREGATE) == 0) {
+                mAccessCount = null;
+                mRejectCount = null;
+                mAccessDuration = null;
+            } else {
+                scale(mAccessCount, scaleFactor);
+                scale(mRejectCount, scaleFactor);
+                scale(mAccessDuration, scaleFactor);
+            }
+            if ((historyFlag & HISTORY_FLAG_DISCRETE) == 0) {
+                mDiscreteAccesses = null;
+                return;
+            }
+            final int discreteOpCount = getDiscreteAccessCount();
+            for (int i = discreteOpCount - 1; i >= 0; i--) {
+                final AttributedOpEntry op = mDiscreteAccesses.get(i);
+                long opBeginTime = op.getLastAccessTime(OP_FLAGS_ALL);
+                long opEndTime = opBeginTime + op.getLastDuration(OP_FLAGS_ALL);
+                opEndTime = max(opBeginTime, opEndTime);
+                if (opEndTime < beginTimeMillis || opBeginTime > endTimeMillis) {
+                    mDiscreteAccesses.remove(i);
+                }
+            }
         }
 
         private boolean isEmpty() {
             return !hasData(mAccessCount)
                     && !hasData(mRejectCount)
-                    && !hasData(mAccessDuration);
+                    && !hasData(mAccessDuration)
+                    && (mDiscreteAccesses == null);
         }
 
         private boolean hasData(@NonNull LongSparseLongArray array) {
-            return (array != null && array.size() > 0);
+            return array != null && array.size() > 0;
         }
 
         private @Nullable HistoricalOp splice(double fractionToRemove) {
@@ -6141,6 +6338,32 @@
             merge(this::getOrCreateAccessCount, other.mAccessCount);
             merge(this::getOrCreateRejectCount, other.mRejectCount);
             merge(this::getOrCreateAccessDuration, other.mAccessDuration);
+
+            if (other.mDiscreteAccesses == null) {
+                return;
+            }
+            if (mDiscreteAccesses == null) {
+                mDiscreteAccesses = new ArrayList(other.mDiscreteAccesses);
+                return;
+            }
+            List<AttributedOpEntry> historicalDiscreteAccesses = new ArrayList<>();
+            final int otherHistoricalOpCount = other.getDiscreteAccessCount();
+            final int historicalOpCount = getDiscreteAccessCount();
+            int i = 0;
+            int j = 0;
+            while (i < otherHistoricalOpCount || j < historicalOpCount) {
+                if (i == otherHistoricalOpCount) {
+                    historicalDiscreteAccesses.add(mDiscreteAccesses.get(j++));
+                } else if (j == historicalOpCount) {
+                    historicalDiscreteAccesses.add(other.mDiscreteAccesses.get(i++));
+                } else if (mDiscreteAccesses.get(j).getLastAccessTime(OP_FLAGS_ALL)
+                        < other.mDiscreteAccesses.get(i).getLastAccessTime(OP_FLAGS_ALL)) {
+                    historicalDiscreteAccesses.add(mDiscreteAccesses.get(j++));
+                } else {
+                    historicalDiscreteAccesses.add(other.mDiscreteAccesses.get(i++));
+                }
+            }
+            mDiscreteAccesses = historicalDiscreteAccesses;
         }
 
         private void increaseAccessCount(@UidState int uidState, @OpFlags int flags,
@@ -6168,6 +6391,23 @@
             }
         }
 
+        private void addDiscreteAccess(@UidState int uidState, @OpFlags int flag,
+                long discreteAccessTime, long discreteAccessDuration) {
+            List<AttributedOpEntry> discreteAccesses = getOrCreateDiscreteAccesses();
+            LongSparseArray<NoteOpEvent> accessEvents = new LongSparseArray<>();
+            long key = makeKey(uidState, flag);
+            NoteOpEvent note = new NoteOpEvent(discreteAccessTime, discreteAccessDuration, null);
+            accessEvents.append(key, note);
+            AttributedOpEntry access = new AttributedOpEntry(mOp, false, accessEvents, null);
+            for (int i = discreteAccesses.size() - 1; i >= 0; i--) {
+                if (discreteAccesses.get(i).getLastAccessTime(OP_FLAGS_ALL) < discreteAccessTime) {
+                    discreteAccesses.add(i + 1, access);
+                    return;
+                }
+            }
+            discreteAccesses.add(0, access);
+        }
+
         /**
          * Gets the op name.
          *
@@ -6183,6 +6423,33 @@
         }
 
         /**
+         * Gets number of discrete historical app ops.
+         *
+         * @return The number historical app ops.
+         * @see #getOpAt(int)
+         */
+        public @IntRange(from = 0) int getDiscreteAccessCount() {
+            if (mDiscreteAccesses == null) {
+                return 0;
+            }
+            return mDiscreteAccesses.size();
+        }
+
+        /**
+         * Gets the historical op at a given index.
+         *
+         * @param index The index to lookup.
+         * @return The op at the given index.
+         * @see #getOpCount()
+         */
+        public @NonNull AttributedOpEntry getDiscreteAccessAt(@IntRange(from = 0) int index) {
+            if (mDiscreteAccesses == null) {
+                throw new IndexOutOfBoundsException();
+            }
+            return mDiscreteAccesses.get(index);
+        }
+
+        /**
          * Gets the number times the op was accessed (performed) in the foreground.
          *
          * @param flags The flags which are any combination of
@@ -6201,6 +6468,25 @@
         }
 
         /**
+         * Gets the discrete events the op was accessed (performed) in the foreground.
+         *
+         * @param flags The flags which are any combination of
+         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+         * for any flag.
+         * @return The list of discrete ops accessed in the foreground.
+         *
+         * @see #getBackgroundDiscreteAccesses(int)
+         * @see #getDiscreteAccesses(int, int, int)
+         */
+        @NonNull
+        public List<AttributedOpEntry> getForegroundDiscreteAccesses(@OpFlags int flags) {
+            return listForFlagsInStates(mDiscreteAccesses, MAX_PRIORITY_UID_STATE,
+                    resolveFirstUnrestrictedUidState(mOp), flags);
+        }
+
+        /**
          * Gets the number times the op was accessed (performed) in the background.
          *
          * @param flags The flags which are any combination of
@@ -6219,6 +6505,25 @@
         }
 
         /**
+         * Gets the discrete events the op was accessed (performed) in the background.
+         *
+         * @param flags The flags which are any combination of
+         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+         * for any flag.
+         * @return The list of discrete ops accessed in the background.
+         *
+         * @see #getForegroundDiscreteAccesses(int)
+         * @see #getDiscreteAccesses(int, int, int)
+         */
+        @NonNull
+        public List<AttributedOpEntry> getBackgroundDiscreteAccesses(@OpFlags int flags) {
+            return listForFlagsInStates(mDiscreteAccesses, resolveLastRestrictedUidState(mOp),
+                    MIN_PRIORITY_UID_STATE, flags);
+        }
+
+        /**
          * Gets the number times the op was accessed (performed) for a
          * range of uid states.
          *
@@ -6244,6 +6549,26 @@
         }
 
         /**
+         * Gets the discrete events the op was accessed (performed) for a
+         * range of uid states.
+         *
+         * @param flags The flags which are any combination of
+         * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+         * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+         * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+         * for any flag.
+         * @return The discrete the op was accessed in the background.
+         *
+         * @see #getBackgroundDiscreteAccesses(int)
+         * @see #getForegroundDiscreteAccesses(int)
+         */
+        @NonNull
+        public List<AttributedOpEntry> getDiscreteAccesses(@UidState int fromUidState,
+                @UidState int toUidState, @OpFlags int flags) {
+            return listForFlagsInStates(mDiscreteAccesses, fromUidState, toUidState, flags);
+        }
+
+        /**
          * Gets the number times the op was rejected in the foreground.
          *
          * @param flags The flags which are any combination of
@@ -6377,6 +6702,7 @@
             writeLongSparseLongArrayToParcel(mAccessCount, parcel);
             writeLongSparseLongArrayToParcel(mRejectCount, parcel);
             writeLongSparseLongArrayToParcel(mAccessDuration, parcel);
+            writeDiscreteAccessArrayToParcel(mDiscreteAccesses, parcel);
         }
 
         @Override
@@ -6397,7 +6723,11 @@
             if (!equalsLongSparseLongArray(mRejectCount, other.mRejectCount)) {
                 return false;
             }
-            return equalsLongSparseLongArray(mAccessDuration, other.mAccessDuration);
+            if (!equalsLongSparseLongArray(mAccessDuration, other.mAccessDuration)) {
+                return false;
+            }
+            return mDiscreteAccesses == null ? (other.mDiscreteAccesses == null ? true
+                    : false) : mDiscreteAccesses.equals(other.mDiscreteAccesses);
         }
 
         @Override
@@ -6406,6 +6736,7 @@
             result = 31 * result + Objects.hashCode(mAccessCount);
             result = 31 * result + Objects.hashCode(mRejectCount);
             result = 31 * result + Objects.hashCode(mAccessDuration);
+            result = 31 * result + Objects.hashCode(mDiscreteAccesses);
             return result;
         }
 
@@ -6434,6 +6765,13 @@
             return mAccessDuration;
         }
 
+        private @NonNull List<AttributedOpEntry> getOrCreateDiscreteAccesses() {
+            if (mDiscreteAccesses == null) {
+                mDiscreteAccesses = new ArrayList<>();
+            }
+            return mDiscreteAccesses;
+        }
+
         /**
          * Multiplies the entries in the array with the passed in scale factor and
          * rounds the result at up 0.5 boundary.
@@ -6524,6 +6862,32 @@
     }
 
     /**
+     * Returns list of events filtered by UidState and UID flags.
+     *
+     * @param accesses The events list.
+     * @param beginUidState The beginning UID state (inclusive).
+     * @param endUidState The end UID state (inclusive).
+     * @param flags The UID flags.
+     * @return filtered list of events.
+     */
+    private static List<AttributedOpEntry> listForFlagsInStates(List<AttributedOpEntry> accesses,
+            @UidState int beginUidState, @UidState int endUidState, @OpFlags int flags) {
+        List<AttributedOpEntry> result = new ArrayList<>();
+        if (accesses == null) {
+            return result;
+        }
+        int nAccesses = accesses.size();
+        for (int i = 0; i < nAccesses; i++) {
+            AttributedOpEntry entry = accesses.get(i);
+            if (entry.getLastAccessTime(beginUidState, endUidState, flags) == -1) {
+                continue;
+            }
+            result.add(entry);
+        }
+        return result;
+    }
+
+    /**
      * Callback for notification of changes to operation state.
      */
     public interface OnOpChangedListener {
@@ -6746,8 +7110,9 @@
         Objects.requireNonNull(callback, "callback cannot be null");
         try {
             mService.getHistoricalOps(request.mUid, request.mPackageName, request.mAttributionTag,
-                    request.mOpNames, request.mFilter, request.mBeginTimeMillis,
-                    request.mEndTimeMillis, request.mFlags, new RemoteCallback((result) -> {
+                    request.mOpNames, request.mHistoryFlags, request.mFilter,
+                    request.mBeginTimeMillis, request.mEndTimeMillis, request.mFlags,
+                    new RemoteCallback((result) -> {
                 final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
                 final long identity = Binder.clearCallingIdentity();
                 try {
@@ -6785,9 +7150,9 @@
         Objects.requireNonNull(callback, "callback cannot be null");
         try {
             mService.getHistoricalOpsFromDiskRaw(request.mUid, request.mPackageName,
-                    request.mAttributionTag, request.mOpNames, request.mFilter,
-                    request.mBeginTimeMillis, request.mEndTimeMillis, request.mFlags,
-                    new RemoteCallback((result) -> {
+                    request.mAttributionTag, request.mOpNames, request.mHistoryFlags,
+                    request.mFilter, request.mBeginTimeMillis, request.mEndTimeMillis,
+                    request.mFlags, new RemoteCallback((result) -> {
                 final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
                 final long identity = Binder.clearCallingIdentity();
                 try {
@@ -9022,6 +9387,32 @@
         return array;
     }
 
+    private static void writeDiscreteAccessArrayToParcel(
+            @Nullable List<AttributedOpEntry> array, @NonNull Parcel parcel) {
+        if (array != null) {
+            final int size = array.size();
+            parcel.writeInt(size);
+            for (int i = 0; i < size; i++) {
+                array.get(i).writeToParcel(parcel, 0);
+            }
+        } else {
+            parcel.writeInt(-1);
+        }
+    }
+
+    private static @Nullable List<AttributedOpEntry> readDiscreteAccessArrayFromParcel(
+            @NonNull Parcel parcel) {
+        final int size = parcel.readInt();
+        if (size < 0) {
+            return null;
+        }
+        final List<AttributedOpEntry> array = new ArrayList<>(size);
+        for (int i = 0; i < size; i++) {
+            array.add(new AttributedOpEntry(parcel));
+        }
+        return array;
+    }
+
     /**
      * Collects the keys from an array to the result creating the result if needed.
      *
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 062cab4..a6260d6 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1797,6 +1797,7 @@
         }
     }
 
+    @UnsupportedAppUsage
     protected ApplicationPackageManager(ContextImpl context, IPackageManager pm) {
         mContext = context;
         mPM = pm;
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index 445fdd8..477e96b 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -16,11 +16,13 @@
 
 package android.app;
 
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.PowerWhitelistManager;
+import android.os.PowerWhitelistManager.ReasonCode;
 import android.os.PowerWhitelistManager.TempAllowListType;
 
 /**
@@ -31,8 +33,11 @@
  */
 @SystemApi
 public class BroadcastOptions {
-    private long mTemporaryAppWhitelistDuration;
-    private @TempAllowListType int mTemporaryAppWhitelistType;
+    private long mTemporaryAppAllowlistDuration;
+    private @TempAllowListType int mTemporaryAppAllowlistType;
+    private @ReasonCode int mTemporaryAppAllowlistReasonCode =
+            PowerWhitelistManager.REASON_UNKNOWN;
+    private @Nullable String mTemporaryAppAllowlistReason;
     private int mMinManifestReceiverApiLevel = 0;
     private int mMaxManifestReceiverApiLevel = Build.VERSION_CODES.CUR_DEVELOPMENT;
     private boolean mDontSendToRestrictedApps = false;
@@ -42,11 +47,17 @@
      * How long to temporarily put an app on the power allowlist when executing this broadcast
      * to it.
      */
-    static final String KEY_TEMPORARY_APP_WHITELIST_DURATION
-            = "android:broadcast.temporaryAppWhitelistDuration";
+    static final String KEY_TEMPORARY_APP_ALLOWLIST_DURATION
+            = "android:broadcast.temporaryAppAllowlistDuration";
 
-    static final String KEY_TEMPORARY_APP_WHITELIST_TYPE
-            = "android:broadcast.temporaryAppWhitelistType";
+    static final String KEY_TEMPORARY_APP_ALLOWLIST_TYPE
+            = "android:broadcast.temporaryAppAllowlistType";
+
+    static final String KEY_TEMPORARY_APP_ALLOWLIST_REASON_CODE =
+            "android:broadcast.temporaryAppAllowlistReasonCode";
+
+    static final String KEY_TEMPORARY_APP_ALLOWLIST_REASON =
+            "android:broadcast.temporaryAppAllowlistReason";
 
     /**
      * Corresponds to {@link #setMinManifestReceiverApiLevel}.
@@ -80,6 +91,7 @@
     @Deprecated
     public static final int TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED =
             PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
+
     /**
      * @hide
      * @deprecated Use {@link android.os.PowerWhitelistManager#
@@ -99,8 +111,11 @@
 
     /** @hide */
     public BroadcastOptions(Bundle opts) {
-        mTemporaryAppWhitelistDuration = opts.getLong(KEY_TEMPORARY_APP_WHITELIST_DURATION);
-        mTemporaryAppWhitelistType = opts.getInt(KEY_TEMPORARY_APP_WHITELIST_TYPE);
+        mTemporaryAppAllowlistDuration = opts.getLong(KEY_TEMPORARY_APP_ALLOWLIST_DURATION);
+        mTemporaryAppAllowlistType = opts.getInt(KEY_TEMPORARY_APP_ALLOWLIST_TYPE);
+        mTemporaryAppAllowlistReasonCode = opts.getInt(KEY_TEMPORARY_APP_ALLOWLIST_REASON_CODE,
+                PowerWhitelistManager.REASON_UNKNOWN);
+        mTemporaryAppAllowlistReason = opts.getString(KEY_TEMPORARY_APP_ALLOWLIST_REASON);
         mMinManifestReceiverApiLevel = opts.getInt(KEY_MIN_MANIFEST_RECEIVER_API_LEVEL, 0);
         mMaxManifestReceiverApiLevel = opts.getInt(KEY_MAX_MANIFEST_RECEIVER_API_LEVEL,
                 Build.VERSION_CODES.CUR_DEVELOPMENT);
@@ -113,45 +128,70 @@
      * Set a duration for which the system should temporary place an application on the
      * power allowlist when this broadcast is being delivered to it.
      * @param duration The duration in milliseconds; 0 means to not place on allowlist.
+     * @deprecated use {@link #setTemporaryAppAllowlist(long, int, int,  String)} instead.
      */
+    @Deprecated
     @RequiresPermission(anyOf = {android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
             android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
             android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND})
     public void setTemporaryAppWhitelistDuration(long duration) {
-        mTemporaryAppWhitelistDuration = duration;
-        mTemporaryAppWhitelistType =
-                PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
+        setTemporaryAppAllowlist(duration,
+                PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                PowerWhitelistManager.REASON_UNKNOWN, null);
     }
 
     /**
      * Set a duration for which the system should temporary place an application on the
      * power allowlist when this broadcast is being delivered to it, specify the temp allowlist
      * type.
-     * @param type one of {@link TempAllowListType}
      * @param duration the duration in milliseconds; 0 means to not place on allowlist.
+     * @param type one of {@link TempAllowListType}
+     * @param reasonCode one of {@link ReasonCode}, use
+     *                  {@link PowerWhitelistManager#REASON_UNKNOWN} if not sure.
+     * @param reason A human-readable reason explaining why the app is temp allowlisted. Only
+     *               used for logging purposes. Could be null or empty string.
      */
     @RequiresPermission(anyOf = {android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
             android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
             android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND})
-    public void setTemporaryAppWhitelistDuration(@TempAllowListType int type, long duration) {
-        mTemporaryAppWhitelistDuration = duration;
-        mTemporaryAppWhitelistType = type;
+    public void setTemporaryAppAllowlist(long duration, @TempAllowListType int type,
+            @ReasonCode int reasonCode, @Nullable String reason) {
+        mTemporaryAppAllowlistDuration = duration;
+        mTemporaryAppAllowlistType = type;
+        mTemporaryAppAllowlistReasonCode = reasonCode;
+        mTemporaryAppAllowlistReason = reason;
     }
 
     /**
-     * Return {@link #setTemporaryAppWhitelistDuration}.
+     * Return {@link #setTemporaryAppAllowlist}.
      * @hide
      */
-    public long getTemporaryAppWhitelistDuration() {
-        return mTemporaryAppWhitelistDuration;
+    public long getTemporaryAppAllowlistDuration() {
+        return mTemporaryAppAllowlistDuration;
     }
 
     /**
-     * Return {@link #mTemporaryAppWhitelistType}.
+     * Return {@link #mTemporaryAppAllowlistType}.
      * @hide
      */
-    public @TempAllowListType int getTemporaryAppWhitelistType() {
-        return mTemporaryAppWhitelistType;
+    public @TempAllowListType int getTemporaryAppAllowlistType() {
+        return mTemporaryAppAllowlistType;
+    }
+
+    /**
+     * Return {@link #mTemporaryAppAllowlistReasonCode}.
+     * @hide
+     */
+    public @ReasonCode int getTemporaryAppAllowlistReasonCode() {
+        return mTemporaryAppAllowlistReasonCode;
+    }
+
+    /**
+     * Return {@link #mTemporaryAppAllowlistReason}.
+     * @hide
+     */
+    public @Nullable String getTemporaryAppAllowlistReason() {
+        return mTemporaryAppAllowlistReason;
     }
 
     /**
@@ -236,11 +276,17 @@
      */
     public Bundle toBundle() {
         Bundle b = new Bundle();
-        if (mTemporaryAppWhitelistDuration > 0) {
-            b.putLong(KEY_TEMPORARY_APP_WHITELIST_DURATION, mTemporaryAppWhitelistDuration);
+        if (mTemporaryAppAllowlistDuration > 0) {
+            b.putLong(KEY_TEMPORARY_APP_ALLOWLIST_DURATION, mTemporaryAppAllowlistDuration);
         }
-        if (mTemporaryAppWhitelistType != 0) {
-            b.putInt(KEY_TEMPORARY_APP_WHITELIST_TYPE, mTemporaryAppWhitelistType);
+        if (mTemporaryAppAllowlistType != 0) {
+            b.putInt(KEY_TEMPORARY_APP_ALLOWLIST_TYPE, mTemporaryAppAllowlistType);
+        }
+        if (mTemporaryAppAllowlistReasonCode != PowerWhitelistManager.REASON_UNKNOWN) {
+            b.putInt(KEY_TEMPORARY_APP_ALLOWLIST_REASON_CODE, mTemporaryAppAllowlistReasonCode);
+        }
+        if (mTemporaryAppAllowlistReason != null) {
+            b.putString(KEY_TEMPORARY_APP_ALLOWLIST_REASON, mTemporaryAppAllowlistReason);
         }
         if (mMinManifestReceiverApiLevel != 0) {
             b.putInt(KEY_MIN_MANIFEST_RECEIVER_API_LEVEL, mMinManifestReceiverApiLevel);
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 4ad13e1..3a8172e 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -17,6 +17,7 @@
 package android.app;
 
 import android.app.ActivityManager;
+import android.app.ActivityManager.PendingIntentInfo;
 import android.app.ActivityTaskManager;
 import android.app.ApplicationErrorReport;
 import android.app.ApplicationExitInfo;
@@ -248,7 +249,7 @@
             in IBinder token, in String resultWho, int requestCode, in Intent[] intents,
             in String[] resolvedTypes, int flags, in Bundle options, int userId);
     void cancelIntentSender(in IIntentSender sender);
-    String getPackageForIntentSender(in IIntentSender sender);
+    ActivityManager.PendingIntentInfo getInfoForIntentSender(in IIntentSender sender);
     void registerIntentSenderCancelListener(in IIntentSender sender, in IResultReceiver receiver);
     void unregisterIntentSenderCancelListener(in IIntentSender sender, in IResultReceiver receiver);
     void enterSafeMode();
@@ -293,7 +294,6 @@
             int operationType);
     void backupAgentCreated(in String packageName, in IBinder agent, int userId);
     void unbindBackupAgent(in ApplicationInfo appInfo);
-    int getUidForIntentSender(in IIntentSender sender);
     int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll,
             boolean requireFull, in String name, in String callerPackage);
     void addPackageDependency(in String packageName);
@@ -345,7 +345,6 @@
     @UnsupportedAppUsage
     void unregisterProcessObserver(in IProcessObserver observer);
     boolean isIntentSenderTargetedToPackage(in IIntentSender sender);
-    boolean isIntentSenderImmutable(in IIntentSender sender);
     @UnsupportedAppUsage
     void updatePersistentConfiguration(in Configuration values);
     void updatePersistentConfigurationWithAttribution(in Configuration values,
@@ -375,8 +374,6 @@
     void unstableProviderDied(in IBinder connection);
     @UnsupportedAppUsage
     boolean isIntentSenderAnActivity(in IIntentSender sender);
-    boolean isIntentSenderAForegroundService(in IIntentSender sender);
-    boolean isIntentSenderABroadcast(in IIntentSender sender);
     /** @deprecated Use {@link startActivityAsUserWithFeature} instead */
     @UnsupportedAppUsage(maxTargetSdk=29, publicAlternatives="Use {@code android.content.Context#createContextAsUser(android.os.UserHandle, int)} and {@link android.content.Context#startActivity(android.content.Intent)} instead")
     int startActivityAsUser(in IApplicationThread caller, in String callingPackage,
@@ -552,7 +549,7 @@
     /**
      * Add a bare uid to the background restrictions whitelist.  Only the system uid may call this.
      */
-    void backgroundWhitelistUid(int uid);
+    void backgroundAllowlistUid(int uid);
 
     // Start of P transactions
     /**
@@ -711,5 +708,5 @@
     /** Called by PendingIntent.queryIntentComponents() */
     List<ResolveInfo> queryIntentComponentsForIntentSender(in IIntentSender sender, int matchFlags);
 
-    boolean isIntentSenderAService(in IIntentSender sender);
+    int getUidProcessCapabilities(int uid, in String callingPackage);
 }
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index b1c39d3..7bb5d9a 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -60,9 +60,9 @@
     void onActivityForcedResizable(String packageName, int taskId, int reason);
 
     /**
-     * Called when we launched an activity that dismissed the docked stack.
+     * Called when we launched an activity that dismissed the docked task.
      */
-    void onActivityDismissingDockedStack();
+    void onActivityDismissingDockedTask();
 
     /**
      * Called when an activity was requested to be launched on a secondary display but was not
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 8d1076e..b2184fe 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1247,7 +1247,8 @@
                 info, title, parent, id,
                 (Activity.NonConfigurationInstances)lastNonConfigurationInstance,
                 new Configuration(), null /* referrer */, null /* voiceInteractor */,
-                null /* window */, null /* activityConfigCallback */, null /*assistToken*/);
+                null /* window */, null /* activityConfigCallback */, null /*assistToken*/,
+                null /*shareableActivityToken*/);
         return activity;
     }
 
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index 74e6125..6b5f19a 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -158,7 +158,7 @@
                 r.activityInfo = mActivityThread.resolveActivityInfo(r.intent);
             }
             r.activity = mActivityThread.startActivityNow(
-                    mParent, r.id, r.intent, r.activityInfo, r, r.instanceState, instance, r);
+                    mParent, r.id, r.intent, r.activityInfo, r, r.instanceState, instance, r, r);
             if (r.activity == null) {
                 return;
             }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 899cdb5..bc24e97 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -24,6 +24,7 @@
 
 import static java.util.Objects.requireNonNull;
 
+import android.annotation.AttrRes;
 import android.annotation.ColorInt;
 import android.annotation.ColorRes;
 import android.annotation.DimenRes;
@@ -98,6 +99,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.graphics.ColorUtils;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.ContrastColorUtil;
 
@@ -1371,6 +1373,18 @@
     public static final String EXTRA_HANG_UP_INTENT = "android.hangUpIntent";
 
     /**
+     * {@link #extras} key: the color used as a hint for the Answer action button of a
+     * {@link android.app.Notification.CallStyle} notification. This extra is a {@link ColorInt}.
+     */
+    public static final String EXTRA_ANSWER_COLOR = "android.answerColor";
+
+    /**
+     * {@link #extras} key: the color used as a hint for the Decline or Hang Up action button of a
+     * {@link android.app.Notification.CallStyle} notification. This extra is a {@link ColorInt}.
+     */
+    public static final String EXTRA_DECLINE_COLOR = "android.declineColor";
+
+    /**
      * {@link #extras} key: whether the notification should be colorized as
      * supplied to {@link Builder#setColorized(boolean)}.
      */
@@ -3637,11 +3651,6 @@
         private int mCachedContrastColorIsFor = COLOR_INVALID;
 
         /**
-         * A neutral color color that can be used for icons.
-         */
-        private int mNeutralColor = COLOR_INVALID;
-
-        /**
          * Caches an instance of StandardTemplateParams. Note that this may have been used before,
          * so make sure to call {@link StandardTemplateParams#reset()} before using it.
          */
@@ -3654,6 +3663,7 @@
         private boolean mRebuildStyledRemoteViews;
 
         private boolean mTintActionButtons;
+        private boolean mTintWithThemeAccent;
         private boolean mInNightMode;
 
         /**
@@ -3689,6 +3699,7 @@
             mContext = context;
             Resources res = mContext.getResources();
             mTintActionButtons = res.getBoolean(R.bool.config_tintNotificationActionButtons);
+            mTintWithThemeAccent = res.getBoolean(R.bool.config_tintNotificationsWithTheme);
 
             if (res.getBoolean(R.bool.config_enableNightMode)) {
                 Configuration currentConfig = res.getConfiguration();
@@ -4879,12 +4890,10 @@
         }
 
         private void bindPhishingAlertIcon(RemoteViews contentView, StandardTemplateParams p) {
-            // TODO(b/180334837): Get buy-in on this color, or make sure to give this the
-            //  accent color, while still accommodating the colorized state.
             contentView.setDrawableTint(
                     R.id.phishing_alert,
                     false /* targetBackground */,
-                    getPrimaryTextColor(p),
+                    getErrorColor(p),
                     PorterDuff.Mode.SRC_ATOP);
         }
 
@@ -4931,7 +4940,7 @@
             contentView.setDrawableTint(
                     R.id.alerted_icon,
                     false /* targetBackground */,
-                    getNeutralColor(p),
+                    getHeaderIconColor(p),
                     PorterDuff.Mode.SRC_ATOP);
         }
 
@@ -5001,6 +5010,7 @@
             bindNotificationHeader(contentView, p);
             bindLargeIconAndApplyMargin(contentView, p, result);
             boolean showProgress = handleProgressBar(contentView, ex, p);
+            boolean hasSecondLine = showProgress;
             if (p.hasTitle()) {
                 contentView.setViewVisibility(R.id.title, View.VISIBLE);
                 contentView.setTextViewText(R.id.title, processTextSpans(p.title));
@@ -5016,11 +5026,27 @@
                 contentView.setTextViewText(textId, processTextSpans(p.text));
                 setTextViewColorSecondary(contentView, textId, p);
                 contentView.setViewVisibility(textId, View.VISIBLE);
+                hasSecondLine = true;
             }
+            setHeaderlessVerticalMargins(contentView, p, hasSecondLine);
 
             return contentView;
         }
 
+        private static void setHeaderlessVerticalMargins(RemoteViews contentView,
+                StandardTemplateParams p, boolean hasSecondLine) {
+            if (!p.mHeaderless) {
+                return;
+            }
+            int marginDimen = hasSecondLine
+                    ? R.dimen.notification_headerless_margin_twoline
+                    : R.dimen.notification_headerless_margin_oneline;
+            contentView.setViewLayoutMarginDimen(R.id.notification_headerless_view_column,
+                    RemoteViews.MARGIN_TOP, marginDimen);
+            contentView.setViewLayoutMarginDimen(R.id.notification_headerless_view_column,
+                    RemoteViews.MARGIN_BOTTOM, marginDimen);
+        }
+
         private CharSequence processTextSpans(CharSequence text) {
             if (hasForegroundColor() || mInNightMode) {
                 return ContrastColorUtil.clearColorSpans(text);
@@ -5028,10 +5054,9 @@
             return text;
         }
 
-        private void setTextViewColorPrimary(RemoteViews contentView, int id,
+        private void setTextViewColorPrimary(RemoteViews contentView, @IdRes int id,
                 StandardTemplateParams p) {
-            ensureColors(p);
-            contentView.setTextColor(id, mPrimaryTextColor);
+            contentView.setTextColor(id, getPrimaryTextColor(p));
         }
 
         private boolean hasForegroundColor() {
@@ -5039,53 +5064,34 @@
         }
 
         /**
-         * Return the primary text color using the existing template params
-         * @hide
-         */
-        @VisibleForTesting
-        public int getPrimaryTextColor() {
-            return getPrimaryTextColor(mParams);
-        }
-
-        /**
          * @param p the template params to inflate this with
          * @return the primary text color
          * @hide
          */
         @VisibleForTesting
-        public int getPrimaryTextColor(StandardTemplateParams p) {
+        public @ColorInt int getPrimaryTextColor(StandardTemplateParams p) {
             ensureColors(p);
             return mPrimaryTextColor;
         }
 
         /**
-         * Return the secondary text color using the existing template params
-         * @hide
-         */
-        @VisibleForTesting
-        public int getSecondaryTextColor() {
-            return getSecondaryTextColor(mParams);
-        }
-
-        /**
          * @param p the template params to inflate this with
          * @return the secondary text color
          * @hide
          */
         @VisibleForTesting
-        public int getSecondaryTextColor(StandardTemplateParams p) {
+        public @ColorInt int getSecondaryTextColor(StandardTemplateParams p) {
             ensureColors(p);
             return mSecondaryTextColor;
         }
 
-        private void setTextViewColorSecondary(RemoteViews contentView, int id,
+        private void setTextViewColorSecondary(RemoteViews contentView, @IdRes int id,
                 StandardTemplateParams p) {
-            ensureColors(p);
-            contentView.setTextColor(id, mSecondaryTextColor);
+            contentView.setTextColor(id, getSecondaryTextColor(p));
         }
 
         private void ensureColors(StandardTemplateParams p) {
-            int backgroundColor = getBackgroundColor(p);
+            int backgroundColor = getUnresolvedBackgroundColor(p);
             if (mPrimaryTextColor == COLOR_INVALID
                     || mSecondaryTextColor == COLOR_INVALID
                     || mTextColorsAreForBackground != backgroundColor) {
@@ -5188,7 +5194,7 @@
                         R.id.progress, ColorStateList.valueOf(mContext.getColor(
                                 R.color.notification_progress_background_color)));
                 if (getRawColor(p) != COLOR_DEFAULT) {
-                    int color = isColorized(p) ? getPrimaryTextColor(p) : resolveContrastColor(p);
+                    int color = getAccentColor(p);
                     ColorStateList colorStateList = ColorStateList.valueOf(color);
                     contentView.setProgressTintList(R.id.progress, colorStateList);
                     contentView.setProgressIndeterminateTintList(R.id.progress, colorStateList);
@@ -5297,11 +5303,18 @@
         }
 
         private void bindExpandButton(RemoteViews contentView, StandardTemplateParams p) {
-            int color = isColorized(p) ? getPrimaryTextColor(p) : getSecondaryTextColor(p);
-            contentView.setDrawableTint(R.id.expand_button, false, color,
-                    PorterDuff.Mode.SRC_ATOP);
-            contentView.setInt(R.id.expand_button, "setOriginalNotificationColor",
-                    color);
+            // set default colors
+            int textColor = getPrimaryTextColor(p);
+            int pillColor = getProtectionColor(p);
+            contentView.setInt(R.id.expand_button, "setDefaultTextColor", textColor);
+            contentView.setInt(R.id.expand_button, "setDefaultPillColor", pillColor);
+            // Use different highlighted colors except when low-priority mode prevents that
+            if (!p.forceDefaultColor) {
+                textColor = getBackgroundColor(p);
+                pillColor = getAccentColor(p);
+            }
+            contentView.setInt(R.id.expand_button, "setHighlightTextColor", textColor);
+            contentView.setInt(R.id.expand_button, "setHighlightPillColor", pillColor);
         }
 
         private void bindHeaderChronometerAndTime(RemoteViews contentView,
@@ -5432,11 +5445,7 @@
             }
             contentView.setViewVisibility(R.id.app_name_text, View.VISIBLE);
             contentView.setTextViewText(R.id.app_name_text, loadHeaderAppName());
-            if (isColorized(p)) {
-                setTextViewColorPrimary(contentView, R.id.app_name_text, p);
-            } else {
-                contentView.setTextColor(R.id.app_name_text, getSecondaryTextColor(p));
-            }
+            contentView.setTextColor(R.id.app_name_text, getSecondaryTextColor(p));
             return true;
         }
 
@@ -5444,6 +5453,11 @@
             return p.allowColorization && mN.isColorized();
         }
 
+        private boolean isCallActionColorCustomizable(StandardTemplateParams p) {
+            return isColorized(p) && mContext.getResources().getBoolean(
+                    R.bool.config_callNotificationActionColorsRequireColorized);
+        }
+
         private void bindSmallIcon(RemoteViews contentView, StandardTemplateParams p) {
             if (mN.mSmallIcon == null && mN.icon != 0) {
                 mN.mSmallIcon = Icon.createWithResource(mContext, mN.icon);
@@ -5477,12 +5491,28 @@
             big.setViewVisibility(R.id.notification_material_reply_text_3, View.GONE);
             big.setTextViewText(R.id.notification_material_reply_text_3, null);
 
-            final boolean snoozeEnabled = mContext.getContentResolver() != null
-                    && (Settings.Secure.getInt(mContext.getContentResolver(),
-                        Settings.Secure.SHOW_NOTIFICATION_SNOOZE, 0) == 1);
-            int bottomMarginDimen = snoozeEnabled ? 0 : R.dimen.notification_content_margin;
+            // This may get erased by bindSnoozeAction
             big.setViewLayoutMarginDimen(R.id.notification_action_list_margin_target,
-                    RemoteViews.MARGIN_BOTTOM, bottomMarginDimen);
+                    RemoteViews.MARGIN_BOTTOM, R.dimen.notification_content_margin);
+        }
+
+        private void bindSnoozeAction(RemoteViews big, StandardTemplateParams p) {
+            boolean hideSnoozeButton = mN.isForegroundService() || mN.fullScreenIntent != null
+                    || isColorized(p) || p.mViewType == StandardTemplateParams.VIEW_TYPE_HEADS_UP;
+            big.setBoolean(R.id.snooze_button, "setEnabled", !hideSnoozeButton);
+            if (hideSnoozeButton) {
+                // Only hide; NotificationContentView will show it when it adds the click listener
+                big.setViewVisibility(R.id.snooze_button, View.GONE);
+            }
+
+            final boolean snoozeEnabled = !hideSnoozeButton
+                    && mContext.getContentResolver() != null
+                    && (Settings.Secure.getInt(mContext.getContentResolver(),
+                    Settings.Secure.SHOW_NOTIFICATION_SNOOZE, 0) == 1);
+            if (snoozeEnabled) {
+                big.setViewLayoutMarginDimen(R.id.notification_action_list_margin_target,
+                        RemoteViews.MARGIN_BOTTOM, 0);
+            }
         }
 
         /**
@@ -5504,6 +5534,11 @@
             RemoteViews big = applyStandardTemplate(layoutId, p, result);
 
             resetStandardTemplateWithActions(big);
+            bindSnoozeAction(big, p);
+            // color the snooze and bubble actions with the theme color
+            ColorStateList actionColor = ColorStateList.valueOf(getStandardActionColor(p));
+            big.setColorStateList(R.id.snooze_button, "setImageTintList", actionColor);
+            big.setColorStateList(R.id.bubble_button, "setImageTintList", actionColor);
 
             boolean validRemoteInput = false;
 
@@ -5553,8 +5588,7 @@
                         showSpinner ? View.VISIBLE : View.GONE);
                 big.setProgressIndeterminateTintList(
                         R.id.notification_material_reply_progress,
-                        ColorStateList.valueOf(
-                                isColorized(p) ? getPrimaryTextColor(p) : resolveContrastColor(p)));
+                        ColorStateList.valueOf(getAccentColor(p)));
 
                 if (replyText.length > 1 && !TextUtils.isEmpty(replyText[1].getText())
                         && p.maxRemoteInputHistory > 1) {
@@ -5970,14 +6004,14 @@
                 // change the background bgColor
                 CharSequence title = action.title;
                 ColorStateList[] outResultColor = new ColorStateList[1];
-                int background = resolveBackgroundColor(p);
+                int background = getBackgroundColor(p);
                 if (isLegacy()) {
                     title = ContrastColorUtil.clearColorSpans(title);
                 } else {
                     title = ensureColorSpanContrast(title, background, outResultColor);
                 }
                 button.setTextViewText(R.id.action0, processTextSpans(title));
-                int textColor = getPrimaryTextColor(p);
+                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
@@ -5985,9 +6019,11 @@
                     background = outResultColor[0].getDefaultColor();
                     textColor = ContrastColorUtil.resolvePrimaryColor(mContext,
                             background, mInNightMode);
-                } else if (getRawColor(p) != COLOR_DEFAULT && !isColorized(p)
-                        && mTintActionButtons && !mInNightMode) {
-                    textColor = resolveContrastColor(p);
+                } else if (mTintActionButtons && !mInNightMode
+                        && getRawColor(p) != COLOR_DEFAULT && !isColorized(p)) {
+                    textColor = getAccentColor(p);
+                } else {
+                    textColor = getPrimaryTextColor(p);
                 }
                 button.setTextColor(R.id.action0, textColor);
                 // We only want about 20% alpha for the ripple
@@ -6005,11 +6041,7 @@
             } else {
                 button.setTextViewText(R.id.action0, processTextSpans(
                         processLegacyText(action.title)));
-                if (isColorized(p)) {
-                    setTextViewColorPrimary(button, R.id.action0, p);
-                } else if (getRawColor(p) != COLOR_DEFAULT && mTintActionButtons) {
-                    button.setTextColor(R.id.action0, resolveContrastColor(p));
-                }
+                button.setTextColor(R.id.action0, getStandardActionColor(p));
             }
             // CallStyle notifications add action buttons which don't actually exist in mActions,
             //  so we have to omit the index in that case.
@@ -6119,9 +6151,9 @@
         private void processSmallIconColor(Icon smallIcon, RemoteViews contentView,
                 StandardTemplateParams p) {
             boolean colorable = !isLegacy() || getColorUtil().isGrayscaleIcon(mContext, smallIcon);
-            int color = isColorized(p) ? getPrimaryTextColor(p) : resolveContrastColor(p);
+            int color = getSmallIconColor(p);
             contentView.setInt(R.id.icon, "setBackgroundColor",
-                    resolveBackgroundColor(p));
+                    getBackgroundColor(p));
             contentView.setInt(R.id.icon, "setOriginalIconColor",
                     colorable ? color : COLOR_INVALID);
         }
@@ -6136,7 +6168,7 @@
             if (largeIcon != null && isLegacy()
                     && getColorUtil().isGrayscaleIcon(mContext, largeIcon)) {
                 // resolve color will fall back to the default when legacy
-                int color = resolveContrastColor(p);
+                int color = getContrastColor(p);
                 contentView.setInt(R.id.icon, "setOriginalIconColor", color);
             }
         }
@@ -6147,14 +6179,94 @@
             }
         }
 
-        int resolveContrastColor(StandardTemplateParams p) {
+        /**
+         * Gets the standard action button color
+         */
+        private @ColorInt int getStandardActionColor(Notification.StandardTemplateParams p) {
+            return mTintActionButtons || isColorized(p) ? getAccentColor(p) : getNeutralColor(p);
+        }
+
+        /**
+         * Gets a neutral color that can be used for icons or similar that should not stand out.
+         */
+        private @ColorInt int getHeaderIconColor(StandardTemplateParams p) {
+            return isColorized(p) ? getSecondaryTextColor(p) : getNeutralColor(p);
+        }
+
+        /**
+         * Gets the foreground color of the small icon.  If the notification is colorized, this
+         * is the primary text color, otherwise it's the contrast-adjusted app-provided color.
+         */
+        private @ColorInt int getSmallIconColor(StandardTemplateParams p) {
+            return isColorized(p) ? getPrimaryTextColor(p) : getContrastColor(p);
+        }
+
+        /**
+         * Gets the 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 getAccentColor(StandardTemplateParams p) {
+            if (isColorized(p)) {
+                return getPrimaryTextColor(p);
+            }
+            if (mTintWithThemeAccent) {
+                int color = obtainThemeColor(R.attr.colorAccent, 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.
+         */
+        private @ColorInt int getProtectionColor(StandardTemplateParams p) {
+            if (mTintWithThemeAccent && !isColorized(p)) {
+                int color = obtainThemeColor(R.attr.colorBackgroundFloating, COLOR_INVALID);
+                if (color != COLOR_INVALID) {
+                    return color;
+                }
+            }
+            // TODO(b/181048615): What color should we use for the expander pill when colorized
+            return ColorUtils.blendARGB(getPrimaryTextColor(p), getBackgroundColor(p), 0.8f);
+        }
+
+        /**
+         * Gets the theme's error color, or the primary text color for colorized notifications.
+         */
+        private @ColorInt int getErrorColor(StandardTemplateParams p) {
+            if (!isColorized(p)) {
+                int color = obtainThemeColor(R.attr.colorError, COLOR_INVALID);
+                if (color != COLOR_INVALID) {
+                    return color;
+                }
+            }
+            return getPrimaryTextColor(p);
+        }
+
+        /**
+         * Gets the theme's background color
+         */
+        private @ColorInt int getDefaultBackgroundColor() {
+            return obtainThemeColor(R.attr.colorBackground,
+                    mInNightMode ? Color.BLACK : Color.WHITE);
+        }
+
+        /**
+         * Gets the contrast-adjusted version of the color provided by the app.
+         */
+        private @ColorInt int getContrastColor(StandardTemplateParams p) {
             int rawColor = getRawColor(p);
             if (mCachedContrastColorIsFor == rawColor && mCachedContrastColor != COLOR_INVALID) {
                 return mCachedContrastColor;
             }
 
             int color;
-            int background = obtainBackgroundColor();
+            // TODO: Maybe use getBackgroundColor(p) instead -- but doing so could break the cache
+            int background = getDefaultBackgroundColor();
             if (rawColor == COLOR_DEFAULT) {
                 ensureColors(p);
                 color = ContrastColorUtil.resolveDefaultColor(mContext, background, mInNightMode);
@@ -6173,28 +6285,29 @@
         /**
          * Return the raw color of this Notification, which doesn't necessarily satisfy contrast.
          *
-         * @see #resolveContrastColor(StandardTemplateParams) for the contrasted color
+         * @see #getContrastColor(StandardTemplateParams) for the contrasted color
          * @param p the template params to inflate this with
          */
-        private int getRawColor(StandardTemplateParams p) {
+        private @ColorInt int getRawColor(StandardTemplateParams p) {
             if (p.forceDefaultColor) {
                 return COLOR_DEFAULT;
             }
             return mN.color;
         }
 
-        int resolveNeutralColor() {
-            if (mNeutralColor != COLOR_INVALID) {
-                return mNeutralColor;
-            }
-            int background = obtainBackgroundColor();
-            mNeutralColor = ContrastColorUtil.resolveDefaultColor(mContext, background,
+        /**
+         * Gets a neutral palette color; this is a contrast-satisfied version of the default color.
+         * @param p the template params to inflate this with
+         */
+        private @ColorInt int getNeutralColor(StandardTemplateParams p) {
+            int background = getBackgroundColor(p);
+            int neutralColor = ContrastColorUtil.resolveDefaultColor(mContext, background,
                     mInNightMode);
-            if (Color.alpha(mNeutralColor) < 255) {
+            if (Color.alpha(neutralColor) < 255) {
                 // alpha doesn't go well for color filters, so let's blend it manually
-                mNeutralColor = ContrastColorUtil.compositeColors(mNeutralColor, background);
+                neutralColor = ContrastColorUtil.compositeColors(neutralColor, background);
             }
-            return mNeutralColor;
+            return neutralColor;
         }
 
         /**
@@ -6338,8 +6451,11 @@
             return mN;
         }
 
-        private @ColorInt int obtainBackgroundColor() {
-            int defaultColor = mInNightMode ? Color.BLACK : Color.WHITE;
+        /**
+         * Returns the color for the given Theme.DeviceDefault.DayNight attribute, or
+         * defValue if that could not be completed
+         */
+        private @ColorInt int obtainThemeColor(@AttrRes int attrRes, @ColorInt int defaultColor) {
             Resources.Theme theme = mContext.getTheme();
             if (theme == null) {
                 // Running unit tests with mocked context
@@ -6347,7 +6463,7 @@
             }
             theme = new ContextThemeWrapper(mContext, R.style.Theme_DeviceDefault_DayNight)
                     .getTheme();
-            TypedArray ta = theme.obtainStyledAttributes(new int[]{R.attr.colorBackground});
+            TypedArray ta = theme.obtainStyledAttributes(new int[]{attrRes});
             if (ta == null) {
                 return defaultColor;
             }
@@ -6466,7 +6582,11 @@
             return R.layout.notification_material_action_tombstone;
         }
 
-        private int getBackgroundColor(StandardTemplateParams p) {
+        /**
+         * Gets the background color, with {@link #COLOR_DEFAULT} being a valid return value,
+         * which must be resolved by the caller before being used.
+         */
+        private @ColorInt int getUnresolvedBackgroundColor(StandardTemplateParams p) {
             if (isColorized(p)) {
                 return mBackgroundColor != COLOR_INVALID ? mBackgroundColor : getRawColor(p);
             } else {
@@ -6475,33 +6595,17 @@
         }
 
         /**
-         * Gets a neutral color that can be used for icons or similar that should not stand out.
-         * @param p the template params to inflate this with
+         * Same as {@link #getUnresolvedBackgroundColor(StandardTemplateParams)} except that it
+         * also resolves the default color to the background.
          */
-        private int getNeutralColor(StandardTemplateParams p) {
-            if (isColorized(p)) {
-                return getSecondaryTextColor(p);
-            } else {
-                return resolveNeutralColor();
-            }
-        }
-
-        /**
-         * Same as getBackgroundColor but also resolved the default color to the background.
-         * @param p the template params to inflate this with
-         */
-        private int resolveBackgroundColor(StandardTemplateParams p) {
-            int backgroundColor = getBackgroundColor(p);
+        private @ColorInt int getBackgroundColor(StandardTemplateParams p) {
+            int backgroundColor = getUnresolvedBackgroundColor(p);
             if (backgroundColor == COLOR_DEFAULT) {
-                backgroundColor = obtainBackgroundColor();
+                backgroundColor = getDefaultBackgroundColor();
             }
             return backgroundColor;
         }
 
-        private boolean shouldTintActionButtons() {
-            return mTintActionButtons;
-        }
-
         private boolean textColorsNeedInversion() {
             if (mStyle == null || !MediaStyle.class.equals(mStyle.getClass())) {
                 return false;
@@ -6519,7 +6623,7 @@
          *
          * @hide
          */
-        public void setColorPalette(int backgroundColor, int foregroundColor) {
+        public void setColorPalette(@ColorInt int backgroundColor, @ColorInt int foregroundColor) {
             mBackgroundColor = backgroundColor;
             mForegroundColor = foregroundColor;
             mTextColorsAreForBackground = COLOR_INVALID;
@@ -6817,26 +6921,13 @@
                 if (decorationType <= DevFlags.DECORATION_PARTIAL) {
                     template.removeFromParent(R.id.notification_top_line);
                 }
-                if (decorationType != DevFlags.DECORATION_FULL_COMPATIBLE) {
-                    // Change the max content size from 60dp (the compatible size) to 48dp
-                    // (the constrained size).  This is done by increasing the minimum margin
-                    // (implemented as top/bottom margins) and decreasing the extra margin
-                    // (implemented as the height of shrinkable top/bottom views in the column).
-                    template.setViewLayoutMarginDimen(
-                            R.id.notification_headerless_view_column,
-                            RemoteViews.MARGIN_TOP,
-                            R.dimen.notification_headerless_margin_constrained_minimum);
-                    template.setViewLayoutMarginDimen(
-                            R.id.notification_headerless_view_column,
-                            RemoteViews.MARGIN_BOTTOM,
-                            R.dimen.notification_headerless_margin_constrained_minimum);
-                    template.setViewLayoutHeightDimen(
-                            R.id.notification_headerless_margin_extra_top,
-                            R.dimen.notification_headerless_margin_constrained_extra);
-                    template.setViewLayoutHeightDimen(
-                            R.id.notification_headerless_margin_extra_bottom,
-                            R.dimen.notification_headerless_margin_constrained_extra);
-                }
+                // The vertical margins are bigger in the "two-line" scenario than the "one-line"
+                //  scenario, but the 'compatible' decoration state is intended to have 3 lines,
+                //  (1 for the top line views and 2 for the custom views), so in that one case we
+                //  use the smaller 1-line margins. This gives the compatible case 88-16*2=56 dp of
+                //  height, 24dp of which goes to the top line, leaving 32dp for the custom view.
+                boolean hasSecondLine = decorationType != DevFlags.DECORATION_FULL_COMPATIBLE;
+                Builder.setHeaderlessVerticalMargins(template, p, hasSecondLine);
             } else {
                 // also update the end margin to account for the large icon or expander
                 Resources resources = context.getResources();
@@ -8162,16 +8253,14 @@
                         TypedValue.COMPLEX_UNIT_DIP);
             }
             contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor",
-                    mBuilder.isColorized(p)
-                            ? mBuilder.getPrimaryTextColor(p)
-                            : mBuilder.resolveContrastColor(p));
+                    mBuilder.getSmallIconColor(p));
             contentView.setInt(R.id.status_bar_latest_event_content, "setSenderTextColor",
                     mBuilder.getPrimaryTextColor(p));
             contentView.setInt(R.id.status_bar_latest_event_content, "setMessageTextColor",
                     mBuilder.getSecondaryTextColor(p));
             contentView.setInt(R.id.status_bar_latest_event_content,
                     "setNotificationBackgroundColor",
-                    mBuilder.resolveBackgroundColor(p));
+                    mBuilder.getBackgroundColor(p));
             contentView.setBoolean(R.id.status_bar_latest_event_content, "setIsCollapsed",
                     isCollapsed);
             contentView.setIcon(R.id.status_bar_latest_event_content, "setAvatarReplacement",
@@ -8926,14 +9015,7 @@
 
             // If the action buttons should not be tinted, then just use the default
             // notification color. Otherwise, just use the passed-in color.
-            Resources resources = mBuilder.mContext.getResources();
-            Configuration currentConfig = resources.getConfiguration();
-            boolean inNightMode = (currentConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
-                    == Configuration.UI_MODE_NIGHT_YES;
-            int tintColor = mBuilder.shouldTintActionButtons() || mBuilder.isColorized(p)
-                    ? getActionColor(p)
-                    : ContrastColorUtil.resolveColor(mBuilder.mContext,
-                            Notification.COLOR_DEFAULT, inNightMode);
+            int tintColor = mBuilder.getStandardActionColor(p);
 
             container.setDrawableTint(buttonId, false, tintColor,
                     PorterDuff.Mode.SRC_ATOP);
@@ -8989,11 +9071,6 @@
             return view;
         }
 
-        private int getActionColor(StandardTemplateParams p) {
-            return mBuilder.isColorized(p) ? mBuilder.getPrimaryTextColor(p)
-                    : mBuilder.resolveContrastColor(p);
-        }
-
         private RemoteViews makeMediaBigContentView() {
             final int actionCount = Math.min(mBuilder.mActions.size(), MAX_MEDIA_BUTTONS);
             // Dont add an expanded view if there is no more content to be revealed
@@ -9066,6 +9143,8 @@
         private PendingIntent mAnswerIntent;
         private PendingIntent mDeclineIntent;
         private PendingIntent mHangUpIntent;
+        private Integer mAnswerButtonColor;
+        private Integer mDeclineButtonColor;
         private Icon mVerificationIcon;
         private CharSequence mVerificationText;
 
@@ -9176,6 +9255,28 @@
         }
 
         /**
+         * Optional color to be used as a hint for the Answer action button's color.
+         * The system may change this color to ensure sufficient contrast with the background.
+         * The system may choose to disregard this hint if the notification is not colorized.
+         */
+        @NonNull
+        public CallStyle setAnswerButtonColorHint(@ColorInt int color) {
+            mAnswerButtonColor = color;
+            return this;
+        }
+
+        /**
+         * Optional color to be used as a hint for the Decline or Hang Up action button's color.
+         * The system may change this color to ensure sufficient contrast with the background.
+         * The system may choose to disregard this hint if the notification is not colorized.
+         */
+        @NonNull
+        public CallStyle setDeclineButtonColorHint(@ColorInt int color) {
+            mDeclineButtonColor = color;
+            return this;
+        }
+
+        /**
          * @hide
          */
         public boolean displayCustomViewInline() {
@@ -9234,40 +9335,47 @@
         }
 
         @NonNull
-        private Action makeNegativeAction() {
+        private Action makeNegativeAction(@NonNull StandardTemplateParams p) {
             if (mDeclineIntent == null) {
-                return makeAction(R.drawable.ic_call_decline,
+                return makeAction(p, R.drawable.ic_call_decline,
                         R.string.call_notification_hang_up_action,
-                        R.color.call_notification_decline_color, mHangUpIntent);
+                        mDeclineButtonColor, R.color.call_notification_decline_color,
+                        mHangUpIntent);
             } else {
-                return makeAction(R.drawable.ic_call_decline,
+                return makeAction(p, R.drawable.ic_call_decline,
                         R.string.call_notification_decline_action,
-                        R.color.call_notification_decline_color, mDeclineIntent);
+                        mDeclineButtonColor, R.color.call_notification_decline_color,
+                        mDeclineIntent);
             }
         }
 
         @Nullable
-        private Action makeAnswerAction() {
-            return mAnswerIntent == null ? null : makeAction(R.drawable.ic_call_answer,
+        private Action makeAnswerAction(@NonNull StandardTemplateParams p) {
+            return mAnswerIntent == null ? null : makeAction(p, R.drawable.ic_call_answer,
                     R.string.call_notification_answer_action,
-                    R.color.call_notification_answer_color, mAnswerIntent);
+                    mAnswerButtonColor, R.color.call_notification_answer_color,
+                    mAnswerIntent);
         }
 
         @NonNull
-        private Action makeAction(@DrawableRes int icon, @StringRes int title,
-                @ColorRes int colorRes, PendingIntent intent) {
+        private Action makeAction(@NonNull StandardTemplateParams p,
+                @DrawableRes int icon, @StringRes int title,
+                @ColorInt Integer colorInt, @ColorRes int defaultColorRes, PendingIntent intent) {
+            if (colorInt == null || !mBuilder.isCallActionColorCustomizable(p)) {
+                colorInt = mBuilder.mContext.getColor(defaultColorRes);
+            }
             Action action = new Action.Builder(Icon.createWithResource("", icon),
                     new SpannableStringBuilder().append(mBuilder.mContext.getString(title),
-                            new ForegroundColorSpan(mBuilder.mContext.getColor(colorRes)),
+                            new ForegroundColorSpan(colorInt),
                             SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE),
                     intent).build();
             action.getExtras().putBoolean(KEY_ACTION_PRIORITY, true);
             return action;
         }
 
-        private ArrayList<Action> makeActionsList() {
-            final Action negativeAction = makeNegativeAction();
-            final Action answerAction = makeAnswerAction();
+        private ArrayList<Action> makeActionsList(@NonNull StandardTemplateParams p) {
+            final Action negativeAction = makeNegativeAction(p);
+            final Action answerAction = makeAnswerAction(p);
 
             ArrayList<Action> actions = new ArrayList<>(MAX_ACTION_BUTTONS);
             final Action lastAction;
@@ -9304,12 +9412,12 @@
                     .hideLargeIcon(true)
                     .text(text)
                     .summaryText(mBuilder.processLegacyText(mVerificationText));
-            // TODO(b/179178086): hide the snooze button
             RemoteViews contentView = mBuilder.applyStandardTemplate(
                     mBuilder.getCallLayoutResource(), p, null /* result */);
 
             // Bind actions.
             mBuilder.resetStandardTemplateWithActions(contentView);
+            mBuilder.bindSnoozeAction(contentView, p);
             bindCallActions(contentView, p);
 
             // Bind some extra conversation-specific header fields.
@@ -9320,11 +9428,9 @@
 
             // Bind some custom CallLayout properties
             contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor",
-                    mBuilder.isColorized(p)
-                            ? mBuilder.getPrimaryTextColor(p)
-                            : mBuilder.resolveContrastColor(p));
+                    mBuilder.getSmallIconColor(p));
             contentView.setInt(R.id.status_bar_latest_event_content,
-                    "setNotificationBackgroundColor", mBuilder.resolveBackgroundColor(p));
+                    "setNotificationBackgroundColor", mBuilder.getBackgroundColor(p));
             contentView.setIcon(R.id.status_bar_latest_event_content, "setLargeIcon",
                     mBuilder.mN.mLargeIcon);
             contentView.setBundle(R.id.status_bar_latest_event_content, "setData",
@@ -9356,7 +9462,7 @@
 
             // Create the buttons for the generated actions list.
             int i = 0;
-            for (Action action : makeActionsList()) {
+            for (Action action : makeActionsList(p)) {
                 final RemoteViews button = mBuilder.generateActionButton(action, emphasizedMode, p);
                 if (i > 0) {
                     // Clear start margin from non-first buttons to reduce the gap between buttons.
@@ -9369,11 +9475,16 @@
         }
 
         private void bindCallerVerification(RemoteViews contentView, StandardTemplateParams p) {
+            String iconContentDescription = null;
+            boolean showDivider = true;
             if (mVerificationIcon != null) {
                 contentView.setImageViewIcon(R.id.verification_icon, mVerificationIcon);
                 contentView.setDrawableTint(R.id.verification_icon, false /* targetBackground */,
                         mBuilder.getSecondaryTextColor(p), PorterDuff.Mode.SRC_ATOP);
                 contentView.setViewVisibility(R.id.verification_icon, View.VISIBLE);
+                iconContentDescription = mBuilder.mContext.getString(
+                        R.string.notification_verified_content_description);
+                showDivider = false;  // the icon replaces the divider
             } else {
                 contentView.setViewVisibility(R.id.verification_icon, View.GONE);
             }
@@ -9381,8 +9492,17 @@
                 contentView.setTextViewText(R.id.verification_text, mVerificationText);
                 mBuilder.setTextViewColorSecondary(contentView, R.id.verification_text, p);
                 contentView.setViewVisibility(R.id.verification_text, View.VISIBLE);
+                iconContentDescription = null;  // let the app's text take precedence
             } else {
                 contentView.setViewVisibility(R.id.verification_text, View.GONE);
+                showDivider = false;  // no divider if no text
+            }
+            contentView.setContentDescription(R.id.verification_icon, iconContentDescription);
+            if (showDivider) {
+                contentView.setViewVisibility(R.id.verification_divider, View.VISIBLE);
+                mBuilder.setTextViewColorSecondary(contentView, R.id.verification_divider, p);
+            } else {
+                contentView.setViewVisibility(R.id.verification_divider, View.GONE);
             }
         }
 
@@ -9421,6 +9541,12 @@
             if (mHangUpIntent != null) {
                 extras.putParcelable(EXTRA_HANG_UP_INTENT, mHangUpIntent);
             }
+            if (mAnswerButtonColor != null) {
+                extras.putInt(EXTRA_ANSWER_COLOR, mAnswerButtonColor);
+            }
+            if (mDeclineButtonColor != null) {
+                extras.putInt(EXTRA_DECLINE_COLOR, mDeclineButtonColor);
+            }
             fixTitleAndTextExtras(extras);
         }
 
@@ -9447,6 +9573,10 @@
             mAnswerIntent = extras.getParcelable(EXTRA_ANSWER_INTENT);
             mDeclineIntent = extras.getParcelable(EXTRA_DECLINE_INTENT);
             mHangUpIntent = extras.getParcelable(EXTRA_HANG_UP_INTENT);
+            mAnswerButtonColor = extras.containsKey(EXTRA_ANSWER_COLOR)
+                    ? extras.getInt(EXTRA_ANSWER_COLOR) : null;
+            mDeclineButtonColor = extras.containsKey(EXTRA_DECLINE_COLOR)
+                    ? extras.getInt(EXTRA_DECLINE_COLOR) : null;
         }
 
         /**
@@ -11940,6 +12070,7 @@
         boolean mHideTitle;
         boolean mHideActions;
         boolean mHideProgress;
+        boolean mHideSnoozeButton;
         boolean mPromotePicture;
         boolean mAllowActionIcons;
         CharSequence title;
@@ -11957,6 +12088,7 @@
             mHideTitle = false;
             mHideActions = false;
             mHideProgress = false;
+            mHideSnoozeButton = false;
             mPromotePicture = false;
             mAllowActionIcons = false;
             title = null;
@@ -12003,6 +12135,11 @@
             return this;
         }
 
+        final StandardTemplateParams hideSnoozeButton(boolean hideSnoozeButton) {
+            this.mHideSnoozeButton = hideSnoozeButton;
+            return this;
+        }
+
         final StandardTemplateParams promotePicture(boolean promotePicture) {
             this.mPromotePicture = promotePicture;
             return this;
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index 1ff64db..e0e9b62 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -73,6 +73,7 @@
 per-file Fragment.java = file:/services/core/java/com/android/server/wm/OWNERS
 per-file *Task* = file:/services/core/java/com/android/server/wm/OWNERS
 per-file Window* = file:/services/core/java/com/android/server/wm/OWNERS
+per-file ConfigurationController.java = file:/services/core/java/com/android/server/wm/OWNERS
 
 # TODO(b/174932174): determine the ownership of KeyguardManager.java
 
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 671315f..549bd4b 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -16,6 +16,11 @@
 
 package android.app;
 
+import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY;
+import static android.app.ActivityManager.INTENT_SENDER_BROADCAST;
+import static android.app.ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE;
+import static android.app.ActivityManager.INTENT_SENDER_SERVICE;
+
 import android.Manifest.permission;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -25,6 +30,7 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemApi.Client;
 import android.annotation.TestApi;
+import android.app.ActivityManager.PendingIntentInfo;
 import android.compat.Compatibility;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledAfter;
@@ -55,6 +61,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * A description of an Intent and target action to perform with it.  Instances
@@ -122,6 +129,9 @@
     private IBinder mWhitelistToken;
     private ArraySet<CancelListener> mCancelListeners;
 
+    // cached pending intent information
+    private @Nullable PendingIntentInfo mCachedInfo;
+
     /**
      * It is now required to specify either {@link #FLAG_IMMUTABLE}
      * or {@link #FLAG_MUTABLE} when creating a PendingIntent.
@@ -455,15 +465,14 @@
     public static PendingIntent getActivityAsUser(Context context, int requestCode,
             @NonNull Intent intent, int flags, Bundle options, UserHandle user) {
         String packageName = context.getPackageName();
-        String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
-                context.getContentResolver()) : null;
+        String resolvedType = intent.resolveTypeIfNeeded(context.getContentResolver());
         checkFlags(flags, packageName);
         try {
             intent.migrateExtraStreamToClipData(context);
             intent.prepareToLeaveProcess(context);
             IIntentSender target =
                 ActivityManager.getService().getIntentSenderWithFeature(
-                    ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
+                    INTENT_SENDER_ACTIVITY, packageName,
                     context.getAttributionTag(), null, null, requestCode, new Intent[] { intent },
                     resolvedType != null ? new String[] { resolvedType } : null,
                     flags, options, user.getIdentifier());
@@ -596,7 +605,7 @@
         try {
             IIntentSender target =
                 ActivityManager.getService().getIntentSenderWithFeature(
-                    ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
+                    INTENT_SENDER_ACTIVITY, packageName,
                     context.getAttributionTag(), null, null, requestCode, intents, resolvedTypes,
                     flags, options, user.getIdentifier());
             return target != null ? new PendingIntent(target) : null;
@@ -630,7 +639,7 @@
      */
     @SuppressWarnings("AndroidFrameworkPendingIntentMutability")
     public static PendingIntent getBroadcast(Context context, int requestCode,
-            Intent intent, @Flags int flags) {
+            @NonNull Intent intent, @Flags int flags) {
         return getBroadcastAsUser(context, requestCode, intent, flags, context.getUser());
     }
 
@@ -643,14 +652,13 @@
     public static PendingIntent getBroadcastAsUser(Context context, int requestCode,
             Intent intent, int flags, UserHandle userHandle) {
         String packageName = context.getPackageName();
-        String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
-                context.getContentResolver()) : null;
+        String resolvedType = intent.resolveTypeIfNeeded(context.getContentResolver());
         checkFlags(flags, packageName);
         try {
             intent.prepareToLeaveProcess(context);
             IIntentSender target =
                 ActivityManager.getService().getIntentSenderWithFeature(
-                    ActivityManager.INTENT_SENDER_BROADCAST, packageName,
+                    INTENT_SENDER_BROADCAST, packageName,
                     context.getAttributionTag(), null, null, requestCode, new Intent[] { intent },
                     resolvedType != null ? new String[] { resolvedType } : null,
                     flags, null, userHandle.getIdentifier());
@@ -687,7 +695,7 @@
     public static PendingIntent getService(Context context, int requestCode,
             @NonNull Intent intent, @Flags int flags) {
         return buildServicePendingIntent(context, requestCode, intent, flags,
-                ActivityManager.INTENT_SENDER_SERVICE);
+                INTENT_SENDER_SERVICE);
     }
 
     /**
@@ -717,14 +725,13 @@
     public static PendingIntent getForegroundService(Context context, int requestCode,
             @NonNull Intent intent, @Flags int flags) {
         return buildServicePendingIntent(context, requestCode, intent, flags,
-                ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE);
+                INTENT_SENDER_FOREGROUND_SERVICE);
     }
 
     private static PendingIntent buildServicePendingIntent(Context context, int requestCode,
             Intent intent, int flags, int serviceKind) {
         String packageName = context.getPackageName();
-        String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
-                context.getContentResolver()) : null;
+        String resolvedType = intent.resolveTypeIfNeeded(context.getContentResolver());
         checkFlags(flags, packageName);
         try {
             intent.prepareToLeaveProcess(context);
@@ -746,6 +753,7 @@
      * @return Returns a IntentSender object that wraps the sender of PendingIntent
      *
      */
+    @NonNull
     public IntentSender getIntentSender() {
         return new IntentSender(mTarget, mWhitelistToken);
     }
@@ -758,6 +766,7 @@
         try {
             ActivityManager.getService().cancelIntentSender(mTarget);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1000,13 +1009,9 @@
      * @deprecated Renamed to {@link #getCreatorPackage()}.
      */
     @Deprecated
+    @NonNull
     public String getTargetPackage() {
-        try {
-            return ActivityManager.getService()
-                .getPackageForIntentSender(mTarget);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        return getCreatorPackage();
     }
 
     /**
@@ -1024,17 +1029,11 @@
      * only use this information to identify who you expect to be interacting with
      * through a {@link #send} call, not who gave you the PendingIntent.</p>
      *
-     * @return The package name of the PendingIntent, or null if there is
-     * none associated with it.
+     * @return The package name of the PendingIntent.
      */
-    @Nullable
+    @NonNull
     public String getCreatorPackage() {
-        try {
-            return ActivityManager.getService()
-                .getPackageForIntentSender(mTarget);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        return getCachedInfo().getCreatorPackage();
     }
 
     /**
@@ -1056,12 +1055,7 @@
      * none associated with it.
      */
     public int getCreatorUid() {
-        try {
-            return ActivityManager.getService()
-                .getUidForIntentSender(mTarget);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        return getCachedInfo().getCreatorUid();
     }
 
     /**
@@ -1149,18 +1143,12 @@
      * only use this information to identify who you expect to be interacting with
      * through a {@link #send} call, not who gave you the PendingIntent.</p>
      *
-     * @return The user handle of the PendingIntent, or null if there is
-     * none associated with it.
+     * @return The user handle of the PendingIntent
      */
-    @Nullable
+    @NonNull
     public UserHandle getCreatorUserHandle() {
-        try {
-            int uid = ActivityManager.getService()
-                .getUidForIntentSender(mTarget);
-            return uid > 0 ? new UserHandle(UserHandle.getUserId(uid)) : null;
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        int uid = getCachedInfo().getCreatorUid();
+        return UserHandle.getUserHandleForUid(uid);
     }
 
     /**
@@ -1180,12 +1168,7 @@
      * Check if this PendingIntent is marked with {@link #FLAG_IMMUTABLE}.
      */
     public boolean isImmutable() {
-        try {
-            return ActivityManager.getService()
-                    .isIntentSenderImmutable(mTarget);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        return getCachedInfo().isImmutable();
     }
 
     /**
@@ -1193,48 +1176,28 @@
      * {@link #getActivity} or {@link #getActivities}.
      */
     public boolean isActivity() {
-        try {
-            return ActivityManager.getService()
-                .isIntentSenderAnActivity(mTarget);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        return getCachedInfo().getIntentSenderType() == INTENT_SENDER_ACTIVITY;
     }
 
     /**
      * @return TRUE if this {@link PendingIntent} was created with {@link #getForegroundService}.
      */
     public boolean isForegroundService() {
-        try {
-            return ActivityManager.getService()
-                    .isIntentSenderAForegroundService(mTarget);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        return getCachedInfo().getIntentSenderType() == INTENT_SENDER_FOREGROUND_SERVICE;
     }
 
     /**
      * @return TRUE if this {@link PendingIntent} was created with {@link #getService}.
      */
     public boolean isService() {
-        try {
-            return ActivityManager.getService()
-                    .isIntentSenderAService(mTarget);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        return getCachedInfo().getIntentSenderType() == INTENT_SENDER_SERVICE;
     }
 
     /**
      * @return TRUE if this {@link PendingIntent} was created with {@link #getBroadcast}.
      */
     public boolean isBroadcast() {
-        try {
-            return ActivityManager.getService()
-                .isIntentSenderABroadcast(mTarget);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        return getCachedInfo().getIntentSenderType() == INTENT_SENDER_BROADCAST;
     }
 
     /**
@@ -1318,7 +1281,7 @@
         sb.append("PendingIntent{");
         sb.append(Integer.toHexString(System.identityHashCode(this)));
         sb.append(": ");
-        sb.append(mTarget != null ? mTarget.asBinder() : null);
+        sb.append(mTarget.asBinder());
         sb.append('}');
         return sb.toString();
     }
@@ -1326,9 +1289,7 @@
     /** @hide */
     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
-        if (mTarget != null) {
-            proto.write(PendingIntentProto.TARGET, mTarget.asBinder().toString());
-        }
+        proto.write(PendingIntentProto.TARGET, mTarget.asBinder().toString());
         proto.end(token);
     }
 
@@ -1345,8 +1306,7 @@
 
     }
 
-    public static final @android.annotation.NonNull Parcelable.Creator<PendingIntent> CREATOR
-            = new Parcelable.Creator<PendingIntent>() {
+    public static final @NonNull Creator<PendingIntent> CREATOR = new Creator<PendingIntent>() {
         public PendingIntent createFromParcel(Parcel in) {
             IBinder target = in.readStrongBinder();
             return target != null
@@ -1400,11 +1360,11 @@
      * @hide
      */
     public PendingIntent(IIntentSender target) {
-        mTarget = target;
+        mTarget = Objects.requireNonNull(target);
     }
 
     /*package*/ PendingIntent(IBinder target, Object cookie) {
-        mTarget = IIntentSender.Stub.asInterface(target);
+        mTarget = Objects.requireNonNull(IIntentSender.Stub.asInterface(target));
         if (cookie != null) {
             mWhitelistToken = (IBinder)cookie;
         }
@@ -1433,4 +1393,16 @@
          */
         void onCancelled(PendingIntent intent);
     }
+
+    private PendingIntentInfo getCachedInfo() {
+        if (mCachedInfo == null) {
+            try {
+                mCachedInfo = ActivityManager.getService().getInfoForIntentSender(mTarget);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        return mCachedInfo;
+    }
 }
diff --git a/core/java/android/app/PictureInPictureParams.java b/core/java/android/app/PictureInPictureParams.java
index ea7eab2..358ce6a 100644
--- a/core/java/android/app/PictureInPictureParams.java
+++ b/core/java/android/app/PictureInPictureParams.java
@@ -202,7 +202,7 @@
         }
         if (in.readInt() != 0) {
             mUserActions = new ArrayList<>();
-            in.readParcelableList(mUserActions, RemoteAction.class.getClassLoader());
+            in.readTypedList(mUserActions, RemoteAction.CREATOR);
         }
         if (in.readInt() != 0) {
             mSourceRectHint = Rect.CREATOR.createFromParcel(in);
@@ -386,7 +386,7 @@
         }
         if (mUserActions != null) {
             out.writeInt(1);
-            out.writeParcelableList(mUserActions, 0);
+            out.writeTypedList(mUserActions, 0);
         } else {
             out.writeInt(0);
         }
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index 1e38230..f523a7d 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -43,7 +43,7 @@
 
     @Override
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public void onActivityPinned(String packageName, int userId, int taskId, int stackId)
+    public void onActivityPinned(String packageName, int userId, int taskId, int rootTaskId)
             throws RemoteException {
     }
 
@@ -66,7 +66,7 @@
 
     @Override
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public void onActivityDismissingDockedStack() throws RemoteException {
+    public void onActivityDismissingDockedTask() throws RemoteException {
     }
 
     @Override
diff --git a/core/java/android/app/WallpaperColors.java b/core/java/android/app/WallpaperColors.java
index 2d203f57..0a8a734 100644
--- a/core/java/android/app/WallpaperColors.java
+++ b/core/java/android/app/WallpaperColors.java
@@ -16,9 +16,9 @@
 
 package android.app;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.SystemApi;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -30,14 +30,19 @@
 import android.util.Size;
 
 import com.android.internal.graphics.ColorUtils;
+import com.android.internal.graphics.palette.CelebiQuantizer;
 import com.android.internal.graphics.palette.Palette;
-import com.android.internal.graphics.palette.VariationalKMeansQuantizer;
 import com.android.internal.util.ContrastColorUtil;
 
 import java.io.FileOutputStream;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * Provides information about the colors of a wallpaper.
@@ -47,6 +52,13 @@
  * or {@link WallpaperColors#getTertiaryColor()}.
  */
 public final class WallpaperColors implements Parcelable {
+    /**
+     * @hide
+     */
+    @IntDef(prefix = "HINT_", value = {HINT_SUPPORTS_DARK_TEXT, HINT_SUPPORTS_DARK_THEME},
+            flag = true)
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ColorsHints {}
 
     private static final boolean DEBUG_DARK_PIXELS = false;
 
@@ -54,18 +66,14 @@
      * Specifies that dark text is preferred over the current wallpaper for best presentation.
      * <p>
      * eg. A launcher may set its text color to black if this flag is specified.
-     * @hide
      */
-    @SystemApi
     public static final int HINT_SUPPORTS_DARK_TEXT = 1 << 0;
 
     /**
      * Specifies that dark theme is preferred over the current wallpaper for best presentation.
      * <p>
      * eg. A launcher may set its drawer color to black if this flag is specified.
-     * @hide
      */
-    @SystemApi
     public static final int HINT_SUPPORTS_DARK_THEME = 1 << 1;
 
     /**
@@ -94,16 +102,21 @@
     private static final float DARK_PIXEL_CONTRAST = 6f;
     private static final float MAX_DARK_AREA = 0.025f;
 
-    private final ArrayList<Color> mMainColors;
+    private final List<Color> mMainColors;
+    private final Map<Integer, Integer> mAllColors;
     private int mColorHints;
 
     public WallpaperColors(Parcel parcel) {
         mMainColors = new ArrayList<>();
+        mAllColors = new HashMap<>();
         final int count = parcel.readInt();
         for (int i = 0; i < count; i++) {
             final int colorInt = parcel.readInt();
             Color color = Color.valueOf(colorInt);
             mMainColors.add(color);
+
+            final int population = parcel.readInt();
+            mAllColors.put(colorInt, population);
         }
         mColorHints = parcel.readInt();
     }
@@ -166,39 +179,22 @@
         }
 
         final Palette palette = Palette
-                .from(bitmap)
-                .setQuantizer(new VariationalKMeansQuantizer())
-                .maximumColorCount(5)
-                .clearFilters()
+                .from(bitmap, new CelebiQuantizer())
+                .maximumColorCount(256)
                 .resizeBitmapArea(MAX_WALLPAPER_EXTRACTION_AREA)
                 .generate();
-
         // Remove insignificant colors and sort swatches by population
         final ArrayList<Palette.Swatch> swatches = new ArrayList<>(palette.getSwatches());
-        final float minColorArea = bitmap.getWidth() * bitmap.getHeight() * MIN_COLOR_OCCURRENCE;
-        swatches.removeIf(s -> s.getPopulation() < minColorArea);
         swatches.sort((a, b) -> b.getPopulation() - a.getPopulation());
 
         final int swatchesSize = swatches.size();
-        Color primary = null, secondary = null, tertiary = null;
 
-        swatchLoop:
+        final Map<Integer, Integer> populationByColor = new HashMap<>();
         for (int i = 0; i < swatchesSize; i++) {
-            Color color = Color.valueOf(swatches.get(i).getRgb());
-            switch (i) {
-                case 0:
-                    primary = color;
-                    break;
-                case 1:
-                    secondary = color;
-                    break;
-                case 2:
-                    tertiary = color;
-                    break;
-                default:
-                    // out of bounds
-                    break swatchLoop;
-            }
+            Palette.Swatch swatch = swatches.get(i);
+            int colorInt = swatch.getInt();
+            populationByColor.put(colorInt, swatch.getPopulation());
+
         }
 
         int hints = calculateDarkHints(bitmap);
@@ -207,7 +203,7 @@
             bitmap.recycle();
         }
 
-        return new WallpaperColors(primary, secondary, tertiary, HINT_FROM_BITMAP | hints);
+        return new WallpaperColors(populationByColor, HINT_FROM_BITMAP | hints);
     }
 
     /**
@@ -238,24 +234,25 @@
      * @param primaryColor Primary color.
      * @param secondaryColor Secondary color.
      * @param tertiaryColor Tertiary color.
-     * @param colorHints A combination of WallpaperColor hints.
-     * @see WallpaperColors#HINT_SUPPORTS_DARK_TEXT
+     * @param colorHints A combination of color hints.
      * @see WallpaperColors#fromBitmap(Bitmap)
      * @see WallpaperColors#fromDrawable(Drawable)
-     * @hide
      */
-    @SystemApi
     public WallpaperColors(@NonNull Color primaryColor, @Nullable Color secondaryColor,
-            @Nullable Color tertiaryColor, int colorHints) {
+            @Nullable Color tertiaryColor, @ColorsHints int colorHints) {
 
         if (primaryColor == null) {
             throw new IllegalArgumentException("Primary color should never be null.");
         }
 
         mMainColors = new ArrayList<>(3);
+        mAllColors = new HashMap<>();
+
         mMainColors.add(primaryColor);
+        mAllColors.put(primaryColor.toArgb(), 0);
         if (secondaryColor != null) {
             mMainColors.add(secondaryColor);
+            mAllColors.put(secondaryColor.toArgb(), 0);
         }
         if (tertiaryColor != null) {
             if (secondaryColor == null) {
@@ -263,8 +260,33 @@
                         + "secondaryColor is null");
             }
             mMainColors.add(tertiaryColor);
+            mAllColors.put(tertiaryColor.toArgb(), 0);
         }
+        mColorHints = colorHints;
+    }
 
+    /**
+     * Constructs a new object from a set of colors, where hints can be specified.
+     *
+     * @param populationByColor Map with keys of colors, and value representing the number of
+     *                          occurrences of color in the wallpaper.
+     * @param colorHints        A combination of color hints.
+     * @hide
+     * @see WallpaperColors#HINT_SUPPORTS_DARK_TEXT
+     * @see WallpaperColors#fromBitmap(Bitmap)
+     * @see WallpaperColors#fromDrawable(Drawable)
+     */
+    public WallpaperColors(@NonNull Map<Integer, Integer> populationByColor,
+            @ColorsHints int colorHints) {
+        mAllColors = populationByColor;
+
+        ArrayList<Map.Entry<Integer, Integer>> mapEntries = new ArrayList(
+                populationByColor.entrySet());
+        mapEntries.sort((a, b) ->
+                a.getValue().compareTo(b.getValue())
+        );
+        mMainColors = mapEntries.stream().map(entry -> Color.valueOf(entry.getKey())).collect(
+                Collectors.toList());
         mColorHints = colorHints;
     }
 
@@ -293,6 +315,9 @@
         for (int i = 0; i < count; i++) {
             Color color = mainColors.get(i);
             dest.writeInt(color.toArgb());
+            Integer population = mAllColors.get(color.toArgb());
+            int populationInt = (population != null) ? population : 0;
+            dest.writeInt(populationInt);
         }
         dest.writeInt(mColorHints);
     }
@@ -336,6 +361,17 @@
         return Collections.unmodifiableList(mMainColors);
     }
 
+    /**
+     * Map of all colors. Key is rgb integer, value is importance of color.
+     *
+     * @return List of colors.
+     * @hide
+     */
+    public @NonNull Map<Integer, Integer> getAllColors() {
+        return Collections.unmodifiableMap(mAllColors);
+    }
+
+
     @Override
     public boolean equals(@Nullable Object o) {
         if (o == null || getClass() != o.getClass()) {
@@ -353,27 +389,14 @@
     }
 
     /**
-     * Combination of WallpaperColor hints.
-     *
-     * @see WallpaperColors#HINT_SUPPORTS_DARK_TEXT
-     * @return True if dark text is supported.
-     * @hide
+     * Returns the color hints for this instance.
+     * @return The color hints.
      */
-    @SystemApi
-    public int getColorHints() {
+    public @ColorsHints int getColorHints() {
         return mColorHints;
     }
 
     /**
-     * @param colorHints Combination of WallpaperColors hints.
-     * @see WallpaperColors#HINT_SUPPORTS_DARK_TEXT
-     * @hide
-     */
-    public void setColorHints(int colorHints) {
-        mColorHints = colorHints;
-    }
-
-    /**
      * Checks if image is bright and clean enough to support light text.
      *
      * @param source What to read.
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index 4ae1670..d04ca1d9 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -57,7 +57,7 @@
      * TODO: Investigate combining with {@link #mAppBounds}. Can the latter be a product of the
      * former?
      */
-    private Rect mBounds = new Rect();
+    private final Rect mBounds = new Rect();
 
     /**
      * {@link android.graphics.Rect} defining app bounds. The dimensions override usages of
@@ -71,7 +71,7 @@
      * The maximum {@link Rect} bounds that an app can expect. It is used to report value of
      * {@link WindowManager#getMaximumWindowMetrics()}.
      */
-    private Rect mMaxBounds = new Rect();
+    private final Rect mMaxBounds = new Rect();
 
     /**
      * The current rotation of this window container relative to the default
@@ -240,9 +240,9 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeParcelable(mBounds, flags);
-        dest.writeParcelable(mAppBounds, flags);
-        dest.writeParcelable(mMaxBounds, flags);
+        mBounds.writeToParcel(dest, flags);
+        dest.writeTypedObject(mAppBounds, flags);
+        mMaxBounds.writeToParcel(dest, flags);
         dest.writeInt(mWindowingMode);
         dest.writeInt(mActivityType);
         dest.writeInt(mAlwaysOnTop);
@@ -250,10 +250,11 @@
         dest.writeInt(mDisplayWindowingMode);
     }
 
-    private void readFromParcel(Parcel source) {
-        mBounds = source.readParcelable(Rect.class.getClassLoader());
-        mAppBounds = source.readParcelable(Rect.class.getClassLoader());
-        mMaxBounds = source.readParcelable(Rect.class.getClassLoader());
+    /** @hide */
+    public void readFromParcel(@NonNull Parcel source) {
+        mBounds.readFromParcel(source);
+        mAppBounds = source.readTypedObject(Rect.CREATOR);
+        mMaxBounds.readFromParcel(source);
         mWindowingMode = source.readInt();
         mActivityType = source.readInt();
         mAlwaysOnTop = source.readInt();
@@ -693,9 +694,7 @@
         }
         protoOutputStream.write(WINDOWING_MODE, mWindowingMode);
         protoOutputStream.write(ACTIVITY_TYPE, mActivityType);
-        if (mBounds != null) {
-            mBounds.dumpDebug(protoOutputStream, BOUNDS);
-        }
+        mBounds.dumpDebug(protoOutputStream, BOUNDS);
         mMaxBounds.dumpDebug(protoOutputStream, MAX_BOUNDS);
         protoOutputStream.end(token);
     }
@@ -719,11 +718,9 @@
                         mAppBounds.readFromProto(proto, APP_BOUNDS);
                         break;
                     case (int) BOUNDS:
-                        mBounds = new Rect();
                         mBounds.readFromProto(proto, BOUNDS);
                         break;
                     case (int) MAX_BOUNDS:
-                        mMaxBounds = new Rect();
                         mMaxBounds.readFromProto(proto, MAX_BOUNDS);
                         break;
                     case (int) WINDOWING_MODE:
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 721a444..cccc929 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -585,6 +585,9 @@
      * @param intent The received intent as per {@link #onReceive}.
      */
     public void onEnabled(@NonNull Context context, @NonNull Intent intent) {
+        if (LOCAL_LOGV) {
+            Log.v(TAG, getClass().getName() + ".onEnabled() on user " + context.getUserId());
+        }
     }
 
     /**
@@ -600,6 +603,10 @@
      */
     public @Nullable CharSequence onDisableRequested(@NonNull Context context,
             @NonNull Intent intent) {
+        if (LOCAL_LOGV) {
+            Log.v(TAG, getClass().getName() + ".onDisableRequested() on user "
+                    + context.getUserId());
+        }
         return null;
     }
 
@@ -612,6 +619,9 @@
      * @param intent The received intent as per {@link #onReceive}.
      */
     public void onDisabled(@NonNull Context context, @NonNull Intent intent) {
+        if (LOCAL_LOGV) {
+            Log.v(TAG, getClass().getName() + ".onDisabled() on user " + context.getUserId());
+        }
     }
 
     /**
@@ -786,6 +796,10 @@
      * @param intent The received intent as per {@link #onReceive}.
      */
     public void onProfileProvisioningComplete(@NonNull Context context, @NonNull Intent intent) {
+        if (LOCAL_LOGV) {
+            Log.v(TAG, getClass().getName() + ".onProfileProvisioningComplete() on user "
+                    + context.getUserId());
+        }
     }
 
     /**
@@ -961,6 +975,9 @@
      */
     public void onUserAdded(@NonNull Context context, @NonNull Intent intent,
             @NonNull UserHandle addedUser) {
+        if (LOCAL_LOGV) {
+            Log.v(TAG, getClass().getName() + ".onUserAdded() on user " + context.getUserId());
+        }
     }
 
     /**
@@ -974,6 +991,9 @@
      */
     public void onUserRemoved(@NonNull Context context, @NonNull Intent intent,
             @NonNull UserHandle removedUser) {
+        if (LOCAL_LOGV) {
+            Log.v(TAG, getClass().getName() + ".onUserRemoved() on user " + context.getUserId());
+        }
     }
 
     /**
@@ -987,6 +1007,9 @@
      */
     public void onUserStarted(@NonNull Context context, @NonNull Intent intent,
             @NonNull UserHandle startedUser) {
+        if (LOCAL_LOGV) {
+            Log.v(TAG, getClass().getName() + ".onUserStarted() on user " + context.getUserId());
+        }
     }
 
     /**
@@ -1000,6 +1023,9 @@
      */
     public void onUserStopped(@NonNull Context context, @NonNull Intent intent,
             @NonNull UserHandle stoppedUser) {
+        if (LOCAL_LOGV) {
+            Log.v(TAG, getClass().getName() + ".onUserStopped() on user " + context.getUserId());
+        }
     }
 
     /**
@@ -1013,6 +1039,9 @@
      */
     public void onUserSwitched(@NonNull Context context, @NonNull Intent intent,
             @NonNull UserHandle switchedUser) {
+        if (LOCAL_LOGV) {
+            Log.v(TAG, getClass().getName() + ".onUserSwitched() on user " + context.getUserId());
+        }
     }
 
     /**
@@ -1104,7 +1133,8 @@
     public void onReceive(@NonNull Context context, @NonNull Intent intent) {
         String action = intent.getAction();
         if (LOCAL_LOGV) {
-            Log.v(TAG, "onReceive(): received " + action + " on user " + context.getUserId());
+            Log.v(TAG, getClass().getName() + ".onReceive(): received " + action + " on user "
+                    + context.getUserId());
         }
 
         if (ACTION_PASSWORD_CHANGED.equals(action)) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 59e5144..b919bfc 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2746,6 +2746,32 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface PersonalAppsSuspensionReason {}
 
+    /**
+     * The default device owner type for a managed device.
+     *
+     * @hide
+     */
+    public static final int DEVICE_OWNER_TYPE_DEFAULT = 0;
+
+    /**
+     * The device owner type for a financed device.
+     *
+     * @hide
+     */
+    public static final int DEVICE_OWNER_TYPE_FINANCED = 1;
+
+    /**
+     * Different device owner types for a managed device.
+     *
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "DEVICE_OWNER_TYPE_" }, value = {
+            DEVICE_OWNER_TYPE_DEFAULT,
+            DEVICE_OWNER_TYPE_FINANCED
+    })
+    public @interface DeviceOwnerType {}
+
     /** @hide */
     @TestApi
     public static final int OPERATION_LOCK_NOW = 1;
@@ -7276,7 +7302,12 @@
     /**
      * @hide
      */
+    @TestApi
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.MANAGE_DEVICE_ADMINS,
+            android.Manifest.permission.INTERACT_ACROSS_USERS_FULL
+    })
     public void setActiveAdmin(@NonNull ComponentName policyReceiver, boolean refreshing,
             int userHandle) {
         if (mService != null) {
@@ -7453,8 +7484,10 @@
      * @throws IllegalArgumentException if the package name is null or invalid
      * @throws IllegalStateException If the preconditions mentioned are not met.
      */
-    public boolean setDeviceOwner(ComponentName who, String ownerName, int userId)
-            throws IllegalArgumentException, IllegalStateException {
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+    public boolean setDeviceOwner(
+            @NonNull ComponentName who, @Nullable String ownerName, @UserIdInt int userId) {
         if (mService != null) {
             try {
                 return mService.setDeviceOwner(who, ownerName, userId);
@@ -7521,7 +7554,10 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS,
+    })
     public ComponentName getDeviceOwnerComponentOnAnyUser() {
         return getDeviceOwnerComponentInner(/* callingUserOnly =*/ false);
     }
@@ -10477,9 +10513,10 @@
 
     /**
      * Reset record of previous system update freeze period the device went through.
-     * Only callable by ADB.
      * @hide
      */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.CLEAR_FREEZE_PERIOD)
     public void clearSystemUpdatePolicyFreezePeriodRecord() {
         throwIfParentInstance("clearSystemUpdatePolicyFreezePeriodRecord");
         if (mService == null) {
@@ -11207,9 +11244,11 @@
 
     /**
      * Makes all accumulated network logs available to DPC in a new batch.
-     * Only callable by ADB. If throttled, returns time to wait in milliseconds, otherwise 0.
+     * If throttled, returns time to wait in milliseconds, otherwise 0.
      * @hide
      */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS)
     public long forceNetworkLogs() {
         if (mService == null) {
             return -1;
@@ -11223,9 +11262,11 @@
 
     /**
      * Forces a batch of security logs to be fetched from logd and makes it available for DPC.
-     * Only callable by ADB. If throttled, returns time to wait in milliseconds, otherwise 0.
+     * If throttled, returns time to wait in milliseconds, otherwise 0.
      * @hide
      */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS)
     public long forceSecurityLogs() {
         if (mService == null) {
             return 0;
@@ -11657,7 +11698,10 @@
      * @throws SecurityException if the caller is not shell / root or the admin package
      *         isn't a test application see {@link ApplicationInfo#FLAG_TEST_APP}.
      */
-    public void forceRemoveActiveAdmin(ComponentName adminReceiver, int userHandle) {
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+    public void forceRemoveActiveAdmin(
+            @NonNull ComponentName adminReceiver, @UserIdInt int userHandle) {
         try {
             mService.forceRemoveActiveAdmin(adminReceiver, userHandle);
         } catch (RemoteException re) {
@@ -12195,8 +12239,9 @@
      *
      * @hide
      */
-    public Set<String> getDisallowedSystemApps(ComponentName admin, int userId,
-            String provisioningAction) {
+    @TestApi
+    public @NonNull Set<String> getDisallowedSystemApps(@NonNull ComponentName admin,
+            @UserIdInt int userId, @NonNull String provisioningAction) {
         try {
             return new ArraySet<>(
                     mService.getDisallowedSystemApps(admin, userId, provisioningAction));
@@ -12727,8 +12772,11 @@
      *
      * @hide
      */
-    @RequiresPermission(value = android.Manifest.permission.MARK_DEVICE_ORGANIZATION_OWNED,
-            conditional = true)
+    @TestApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MARK_DEVICE_ORGANIZATION_OWNED,
+            android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS
+    }, conditional = true)
     public void markProfileOwnerOnOrganizationOwnedDevice(@NonNull ComponentName who) {
         if (mService == null) {
             return;
@@ -12957,6 +13005,7 @@
      *
      * @hide
      */
+    @TestApi
     public @NonNull Set<String> getDefaultCrossProfilePackages() {
         throwIfParentInstance("getDefaultCrossProfilePackages");
         if (mService != null) {
@@ -13460,6 +13509,57 @@
     }
 
     /**
+     * Sets the device owner type for a managed device (e.g. financed device).
+     *
+     * @param admin The {@link DeviceAdminReceiver} that is the device owner.
+     * @param deviceOwnerType The device owner type is set to. Use
+     * {@link #DEVICE_OWNER_TYPE_DEFAULT} for the default device owner type. Use
+     * {@link #DEVICE_OWNER_TYPE_FINANCED} for the financed device owner type.
+     *
+     * @throws IllegalStateException When admin is not the device owner, or there is no device
+     *     owner, or attempting to set the device owner type again for the same admin.
+     * @throws SecurityException If the caller does not have the permission
+     *     {@link permission#MANAGE_PROFILE_AND_DEVICE_OWNERS}.
+     *
+     * @hide
+     */
+    public void setDeviceOwnerType(@NonNull ComponentName admin,
+            @DeviceOwnerType int deviceOwnerType) {
+        throwIfParentInstance("setDeviceOwnerType");
+        if (mService != null) {
+            try {
+                mService.setDeviceOwnerType(admin, deviceOwnerType);
+            } catch (RemoteException re) {
+                throw re.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Returns the device owner type for the admin used in
+     * {@link #setDeviceOwnerType(ComponentName, int)}. {@link #DEVICE_OWNER_TYPE_DEFAULT}
+     * would be returned when the device owner type is not set for the device owner admin.
+     *
+     * @param admin The {@link DeviceAdminReceiver} that is the device owner.
+     *
+     * @throws IllegalStateException When admin is not the device owner or there is no device owner.
+     *
+     * @hide
+     */
+    @DeviceOwnerType
+    public int getDeviceOwnerType(@NonNull ComponentName admin) {
+        throwIfParentInstance("getDeviceOwnerType");
+        if (mService != null) {
+            try {
+                return mService.getDeviceOwnerType(admin);
+            } catch (RemoteException re) {
+                throw re.rethrowFromSystemServer();
+            }
+        }
+        return DEVICE_OWNER_TYPE_DEFAULT;
+    }
+
+    /**
      * Called by device owner or profile owner of an organization-owned managed profile to
      * enable or disable USB data signaling for the device. When disabled, USB data connections
      * (except from charging functions) are prohibited.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 8a87b16..ac1592d 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -503,6 +503,9 @@
     UserHandle createAndProvisionManagedProfile(in ManagedProfileProvisioningParams provisioningParams, in String callerPackage);
     void provisionFullyManagedDevice(in FullyManagedDeviceProvisioningParams provisioningParams, in String callerPackage);
 
+    void setDeviceOwnerType(in ComponentName admin, in int deviceOwnerType);
+    int getDeviceOwnerType(in ComponentName admin);
+
     void resetDefaultCrossProfileIntentFilters(int userId);
     boolean canAdminGrantSensorsPermissionsForUser(int userId);
 
diff --git a/core/java/android/app/assist/ActivityId.java b/core/java/android/app/assist/ActivityId.java
new file mode 100644
index 0000000..fb0d056
--- /dev/null
+++ b/core/java/android/app/assist/ActivityId.java
@@ -0,0 +1,125 @@
+/*
+ * 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.assist;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.service.contentcapture.ContentCaptureService;
+import android.view.contentcapture.ContentCaptureContext;
+import android.view.translation.UiTranslationManager;
+
+import com.android.internal.annotations.Immutable;
+
+/**
+ * The class is used to identify an instance of an Activity. The system provides this to services
+ * that need to request operations on a specific Activity. For example, the system provides this in
+ * {@link ContentCaptureContext} to {@link ContentCaptureService} which can use it to issue requests
+ * like {@link UiTranslationManager#startTranslation}.
+ *
+ * @hide
+ */
+@Immutable
+@SystemApi
+public class ActivityId {
+
+    /**
+     * The identifier of the task this activity is in.
+     */
+    private final int mTaskId;
+    /**
+     * The identifier of the activity.
+     */
+    @Nullable
+    private final IBinder mActivityId;
+
+    /**
+     * @hide
+     */
+    public ActivityId(int taskId, @Nullable IBinder activityId) {
+        mTaskId = taskId;
+        mActivityId = activityId;
+    }
+
+    /**
+     * @hide
+     */
+    public ActivityId(@NonNull Parcel source) {
+        mTaskId = source.readInt();
+        mActivityId = source.readStrongBinder();
+    }
+
+    /**
+     * The identifier of the task this activity is in.
+     * @hide
+     */
+    @TestApi
+    public int getTaskId() {
+        return mTaskId;
+    }
+
+    /**
+     * The identifier of the activity. In some case, this value may be null, e.g. the child session
+     * of content capture.
+     * @hide
+     */
+    @Nullable
+    @TestApi
+    public IBinder getToken() {
+        return mActivityId;
+    }
+
+    /**
+     * @hide
+     */
+    public void writeToParcel(@NonNull Parcel dest, int parcelableFlags) {
+        dest.writeInt(mTaskId);
+        dest.writeStrongBinder(mActivityId);
+    }
+
+    @Override
+    public String toString() {
+        return "ActivityId { taskId = " + mTaskId + ", activityId = " + mActivityId + " }";
+    }
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        ActivityId that = (ActivityId) o;
+        if (mTaskId != that.mTaskId) {
+            return false;
+        }
+        return mActivityId != null
+                ? mActivityId.equals(that.mActivityId)
+                : that.mActivityId == null;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = mTaskId;
+        result = 31 * result + (mActivityId != null ? mActivityId.hashCode() : 0);
+        return result;
+    }
+}
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 85cfe83..22492cc 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -564,10 +564,6 @@
     @VisibleForTesting
     public IncludeExcludeRules getIncludeExcludeRules(FullBackup.BackupScheme backupScheme)
             throws IOException, XmlPullParserException {
-        if (isDeviceToDeviceMigration()) {
-            return IncludeExcludeRules.emptyRules();
-        }
-
         Map<String, Set<PathWithRequiredFlags>> manifestIncludeMap;
         ArraySet<PathWithRequiredFlags> manifestExcludeSet;
 
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 673de8f..dae565e 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -361,36 +361,7 @@
             try {
                 // All packages, current transport
                 IRestoreSession binder =
-                        sService.beginRestoreSessionForUser(mContext.getUserId(), null, null,
-                                OperationType.BACKUP);
-                if (binder != null) {
-                    session = new RestoreSession(mContext, binder);
-                }
-            } catch (RemoteException e) {
-                Log.e(TAG, "beginRestoreSession() couldn't connect");
-            }
-        }
-        return session;
-    }
-
-    /**
-     * Begin the process of restoring data from backup.  See the
-     * {@link android.app.backup.RestoreSession} class for documentation on that process.
-     *
-     * @param operationType Type of the operation, see {@link OperationType}
-     *
-     * @hide
-     */
-    @RequiresPermission(android.Manifest.permission.BACKUP)
-    public RestoreSession beginRestoreSession(@OperationType int operationType) {
-        RestoreSession session = null;
-        checkServiceBinder();
-        if (sService != null) {
-            try {
-                // All packages, current transport
-                IRestoreSession binder =
-                        sService.beginRestoreSessionForUser(mContext.getUserId(), null, null,
-                                operationType);
+                        sService.beginRestoreSessionForUser(mContext.getUserId(), null, null);
                 if (binder != null) {
                     session = new RestoreSession(mContext, binder);
                 }
@@ -801,7 +772,7 @@
     @SystemApi
     @RequiresPermission(android.Manifest.permission.BACKUP)
     public int requestBackup(String[] packages, BackupObserver observer) {
-        return requestBackup(packages, observer, null, 0, OperationType.BACKUP);
+        return requestBackup(packages, observer, null, 0);
     }
 
     /**
@@ -826,31 +797,6 @@
     @RequiresPermission(android.Manifest.permission.BACKUP)
     public int requestBackup(String[] packages, BackupObserver observer,
             BackupManagerMonitor monitor, int flags) {
-        return requestBackup(packages, observer, monitor, flags, OperationType.BACKUP);
-    }
-
-    /**
-     * Request an immediate backup, providing an observer to which results of the backup operation
-     * will be published. The Android backup system will decide for each package whether it will
-     * be full app data backup or key/value-pair-based backup.
-     *
-     * <p>If this method returns {@link BackupManager#SUCCESS}, the OS will attempt to backup all
-     * provided packages using the remote transport.
-     *
-     * @param packages List of package names to backup.
-     * @param observer The {@link BackupObserver} to receive callbacks during the backup
-     *                 operation. Could be {@code null}.
-     * @param monitor  The {@link BackupManagerMonitorWrapper} to receive callbacks of important
-     *                 events during the backup operation. Could be {@code null}.
-     * @param flags    {@link #FLAG_NON_INCREMENTAL_BACKUP}.
-     * @param operationType {@link OperationType}
-     * @return {@link BackupManager#SUCCESS} on success; nonzero on error.
-     * @throws IllegalArgumentException on null or empty {@code packages} param.
-     * @hide
-     */
-    @RequiresPermission(android.Manifest.permission.BACKUP)
-    public int requestBackup(String[] packages, BackupObserver observer,
-            BackupManagerMonitor monitor, int flags, @OperationType int operationType) {
         checkServiceBinder();
         if (sService != null) {
             try {
@@ -860,8 +806,7 @@
                 BackupManagerMonitorWrapper monitorWrapper = monitor == null
                         ? null
                         : new BackupManagerMonitorWrapper(monitor);
-                return sService.requestBackup(packages, observerWrapper, monitorWrapper, flags,
-                        operationType);
+                return sService.requestBackup(packages, observerWrapper, monitorWrapper, flags);
             } catch (RemoteException e) {
                 Log.e(TAG, "requestBackup() couldn't connect");
             }
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index f7ed6f1f..829b6cd 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -19,10 +19,16 @@
 import static android.app.backup.BackupManager.OperationType;
 
 import android.annotation.Nullable;
+import android.annotation.StringDef;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.XmlResourceParser;
+import android.os.Build;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.storage.StorageManager;
@@ -33,6 +39,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -94,6 +101,23 @@
             "fakeClientSideEncryption";
 
     /**
+     * When  this change is enabled, include / exclude rules specified via
+     * {@code android:fullBackupContent} are ignored during D2D transfers.
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
+    private static final long IGNORE_FULL_BACKUP_CONTENT_IN_D2D = 180523564L;
+
+    @StringDef({
+        ConfigSection.CLOUD_BACKUP,
+        ConfigSection.DEVICE_TRANSFER
+    })
+    private @interface ConfigSection {
+        String CLOUD_BACKUP = "cloud-backup";
+        String DEVICE_TRANSFER = "device-transfer";
+    }
+
+    /**
      * Identify {@link BackupScheme} object by package and operation type
      * (see {@link OperationType}) it corresponds to.
      */
@@ -273,6 +297,7 @@
         private final static String TAG_INCLUDE = "include";
         private final static String TAG_EXCLUDE = "exclude";
 
+        final int mDataExtractionRules;
         final int mFullBackupContent;
         @OperationType final int mOperationType;
         final PackageManager mPackageManager;
@@ -394,7 +419,10 @@
         ArraySet<PathWithRequiredFlags> mExcludes;
 
         BackupScheme(Context context, @OperationType int operationType) {
-            mFullBackupContent = context.getApplicationInfo().fullBackupContent;
+            ApplicationInfo applicationInfo = context.getApplicationInfo();
+
+            mDataExtractionRules = applicationInfo.dataExtractionRulesRes;
+            mFullBackupContent = applicationInfo.fullBackupContent;
             mOperationType = operationType;
             mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
             mPackageManager = context.getPackageManager();
@@ -468,34 +496,101 @@
             mIncludes = new ArrayMap<String, Set<PathWithRequiredFlags>>();
             mExcludes = new ArraySet<PathWithRequiredFlags>();
 
-            if (mFullBackupContent == 0) {
-                // android:fullBackupContent="true" which means that we'll do everything.
+            if (mFullBackupContent == 0 && mDataExtractionRules == 0) {
+                // No scheme specified via either new or legacy config, will copy everything.
                 if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) {
                     Log.v(FullBackup.TAG_XML_PARSER, "android:fullBackupContent - \"true\"");
                 }
             } else {
-                // android:fullBackupContent="@xml/some_resource".
+                // Scheme is present.
                 if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) {
-                    Log.v(FullBackup.TAG_XML_PARSER,
-                            "android:fullBackupContent - found xml resource");
+                    Log.v(FullBackup.TAG_XML_PARSER, "Found xml scheme: "
+                            + "android:fullBackupContent=" + mFullBackupContent
+                            + "; android:dataExtractionRules=" + mDataExtractionRules);
                 }
-                XmlResourceParser parser = null;
+
                 try {
-                    parser = mPackageManager
-                            .getResourcesForApplication(mPackageName)
-                            .getXml(mFullBackupContent);
-                    parseBackupSchemeFromXmlLocked(parser, mExcludes, mIncludes);
+                    parseSchemeForOperationType(mOperationType);
                 } catch (PackageManager.NameNotFoundException e) {
                     // Throw it as an IOException
                     throw new IOException(e);
-                } finally {
-                    if (parser != null) {
-                        parser.close();
-                    }
                 }
             }
         }
 
+        private void parseSchemeForOperationType(@OperationType int operationType)
+                throws PackageManager.NameNotFoundException, IOException, XmlPullParserException {
+            String configSection = getConfigSectionForOperationType(operationType);
+            if (configSection == null) {
+                Slog.w(TAG, "Given operation type isn't supported by backup scheme: "
+                        + operationType);
+                return;
+            }
+
+            if (mDataExtractionRules != 0) {
+                // New config is present. Use it if it has configuration for this operation
+                // type.
+                try (XmlResourceParser parser = getParserForResource(mDataExtractionRules)) {
+                    parseNewBackupSchemeFromXmlLocked(parser, configSection, mExcludes, mIncludes);
+                }
+                if (!mExcludes.isEmpty() || !mIncludes.isEmpty()) {
+                    // Found configuration in the new config, we will use it.
+                    return;
+                }
+            }
+
+            if (operationType == OperationType.MIGRATION
+                    && CompatChanges.isChangeEnabled(IGNORE_FULL_BACKUP_CONTENT_IN_D2D)) {
+                return;
+            }
+
+            if (mFullBackupContent != 0) {
+                // Fall back to the old config.
+                try (XmlResourceParser parser = getParserForResource(mFullBackupContent)) {
+                    parseBackupSchemeFromXmlLocked(parser, mExcludes, mIncludes);
+                }
+            }
+        }
+
+        @Nullable
+        private String getConfigSectionForOperationType(@OperationType int operationType)  {
+            switch (operationType) {
+                case OperationType.BACKUP:
+                    return ConfigSection.CLOUD_BACKUP;
+                case OperationType.MIGRATION:
+                    return ConfigSection.DEVICE_TRANSFER;
+                default:
+                    return null;
+            }
+        }
+
+        private XmlResourceParser getParserForResource(int resourceId)
+                throws PackageManager.NameNotFoundException {
+            return mPackageManager
+                    .getResourcesForApplication(mPackageName)
+                    .getXml(resourceId);
+        }
+
+        private void parseNewBackupSchemeFromXmlLocked(XmlPullParser parser,
+                @ConfigSection  String configSection,
+                Set<PathWithRequiredFlags> excludes,
+                Map<String, Set<PathWithRequiredFlags>> includes)
+                throws IOException, XmlPullParserException {
+            verifyTopLevelTag(parser, "data-extraction-rules");
+
+            int event;
+            while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
+                if (event != XmlPullParser.START_TAG || !configSection.equals(parser.getName())) {
+                    continue;
+                }
+
+                // TODO(b/180523028): Parse required attributes for rules (e.g. encryption).
+                parseRules(parser, excludes, includes, Optional.of(0), configSection);
+            }
+
+            logParsingResults(excludes, includes);
+        }
+
         @VisibleForTesting
         public void parseBackupSchemeFromXmlLocked(XmlPullParser parser,
                                                    Set<PathWithRequiredFlags> excludes,
@@ -503,7 +598,7 @@
                 throws IOException, XmlPullParserException {
             verifyTopLevelTag(parser, "full-backup-content");
 
-            parseRules(parser, excludes, includes, Optional.empty());
+            parseRules(parser, excludes, includes, Optional.empty(), "full-backup-content");
 
             logParsingResults(excludes, includes);
         }
@@ -532,10 +627,12 @@
         private void parseRules(XmlPullParser parser,
                 Set<PathWithRequiredFlags> excludes,
                 Map<String, Set<PathWithRequiredFlags>> includes,
-                Optional<Integer> maybeRequiredFlags)
+                Optional<Integer> maybeRequiredFlags,
+                String endingTag)
                 throws IOException, XmlPullParserException {
             int event;
-            while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
+            while ((event = parser.next()) != XmlPullParser.END_DOCUMENT
+                    && !parser.getName().equals(endingTag)) {
                 switch (event) {
                     case XmlPullParser.START_TAG:
                         validateInnerTagContents(parser);
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index e1bbc08..bf5be95 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -547,11 +547,9 @@
      *        set can be restored.
      * @param transportID The name of the transport to use for the restore operation.
      *        May be null, in which case the current active transport is used.
-     * @param operationType Type of the operation, see {@link BackupManager#OperationType}
      * @return An interface to the restore session, or null on error.
      */
-    IRestoreSession beginRestoreSessionForUser(int userId, String packageName, String transportID,
-            int operationType);
+    IRestoreSession beginRestoreSessionForUser(int userId, String packageName, String transportID);
 
     /**
      * Notify the backup manager that a BackupAgent has completed the operation
@@ -680,7 +678,7 @@
      * {@link android.app.backup.IBackupManager.requestBackupForUser} for the calling user id.
      */
     int requestBackup(in String[] packages, IBackupObserver observer, IBackupManagerMonitor monitor,
-        int flags, int operationType);
+            int flags);
 
     /**
      * Cancel all running backups. After this call returns, no currently running backups will
diff --git a/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java b/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
index b3f9e31..33f8302 100644
--- a/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
+++ b/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
@@ -19,7 +19,9 @@
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.annotation.UserIdInt;
 import android.graphics.Bitmap;
 import android.os.Binder;
@@ -220,6 +222,72 @@
     }
 
     /**
+     * Resets the temporary service implementation to the default component.
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_SUGGESTIONS)
+    public void resetTemporaryService(@UserIdInt int userId) {
+        if (mService == null) {
+            Log.e(TAG, "resetTemporaryService called, but no ContentSuggestionsManager "
+                    + "configured");
+            return;
+        }
+        try {
+            mService.resetTemporaryService(userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Temporarily sets the service implementation.
+     *
+     * @param userId user Id to set the temporary service on.
+     * @param serviceName name of the new component
+     * @param duration how long the change will be valid (the service will be automatically reset
+     *            to the default component after this timeout expires).
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_SUGGESTIONS)
+    public void setTemporaryService(
+            @UserIdInt int userId, @NonNull String serviceName, int duration) {
+        if (mService == null) {
+            Log.e(TAG, "setTemporaryService called, but no ContentSuggestionsManager "
+                    + "configured");
+            return;
+        }
+        try {
+            mService.setTemporaryService(userId, serviceName, duration);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Sets whether the default service should be used.
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_SUGGESTIONS)
+    public void setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
+        if (mService == null) {
+            Log.e(TAG, "setDefaultServiceEnabled called, but no ContentSuggestionsManager "
+                    + "configured");
+            return;
+        }
+        try {
+            mService.setDefaultServiceEnabled(userId, enabled);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Callback to receive content selections from
      *  {@link #suggestContentSelections(SelectionsRequest, Executor, SelectionsCallback)}.
      */
diff --git a/core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl b/core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl
index 8e6338b..9350eeb 100644
--- a/core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl
+++ b/core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl
@@ -45,4 +45,7 @@
             in IClassificationsCallback callback);
     void notifyInteraction(int userId, in String requestId, in Bundle interaction);
     void isEnabled(int userId, in IResultReceiver receiver);
+    void resetTemporaryService(int userId);
+    void setTemporaryService(int userId, in String serviceName, int duration);
+    void setDefaultServiceEnabled(int userId, boolean enabled);
 }
diff --git a/core/java/android/app/people/PeopleSpaceTile.java b/core/java/android/app/people/PeopleSpaceTile.java
index 132af4b..dd2ba7d 100644
--- a/core/java/android/app/people/PeopleSpaceTile.java
+++ b/core/java/android/app/people/PeopleSpaceTile.java
@@ -29,6 +29,7 @@
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.UserHandle;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -45,7 +46,7 @@
     private String mId;
     private CharSequence mUserName;
     private Icon mUserIcon;
-    private int mUid;
+    private UserHandle mUserHandle;
     private Uri mContactUri;
     private String mPackageName;
     private String mBirthdayText;
@@ -64,7 +65,7 @@
         mUserName = b.mUserName;
         mUserIcon = b.mUserIcon;
         mContactUri = b.mContactUri;
-        mUid = b.mUid;
+        mUserHandle = b.mUserHandle;
         mPackageName = b.mPackageName;
         mBirthdayText = b.mBirthdayText;
         mLastInteractionTimestamp = b.mLastInteractionTimestamp;
@@ -95,8 +96,8 @@
         return mContactUri;
     }
 
-    public int getUid() {
-        return mUid;
+    public UserHandle getUserHandle() {
+        return mUserHandle;
     }
 
     public String getPackageName() {
@@ -165,7 +166,7 @@
         Builder builder =
                 new Builder(mId, mUserName.toString(), mUserIcon, mIntent);
         builder.setContactUri(mContactUri);
-        builder.setUid(mUid);
+        builder.setUserHandle(mUserHandle);
         builder.setPackageName(mPackageName);
         builder.setBirthdayText(mBirthdayText);
         builder.setLastInteractionTimestamp(mLastInteractionTimestamp);
@@ -186,7 +187,7 @@
         private CharSequence mUserName;
         private Icon mUserIcon;
         private Uri mContactUri;
-        private int mUid;
+        private UserHandle mUserHandle;
         private String mPackageName;
         private String mBirthdayText;
         private long mLastInteractionTimestamp;
@@ -212,7 +213,7 @@
             mId = info.getId();
             mUserName = info.getLabel();
             mUserIcon = convertDrawableToIcon(launcherApps.getShortcutIconDrawable(info, 0));
-            mUid = info.getUserId();
+            mUserHandle = info.getUserHandle();
             mPackageName = info.getPackage();
             mContactUri = getContactUri(info);
         }
@@ -222,7 +223,7 @@
             mId = info.getId();
             mUserName = info.getLabel();
             mUserIcon = convertDrawableToIcon(launcherApps.getShortcutIconDrawable(info, 0));
-            mUid = info.getUserId();
+            mUserHandle = info.getUserHandle();
             mPackageName = info.getPackage();
             mContactUri = getContactUri(info);
             mStatuses = channel.getStatuses();
@@ -265,9 +266,9 @@
             return this;
         }
 
-        /** Sets the associated uid. */
-        public Builder setUid(int uid) {
-            mUid = uid;
+        /** Sets the associated {@code userHandle}. */
+        public Builder setUserHandle(UserHandle userHandle) {
+            mUserHandle = userHandle;
             return this;
         }
 
@@ -349,7 +350,7 @@
         mUserName = in.readCharSequence();
         mUserIcon = in.readParcelable(Icon.class.getClassLoader());
         mContactUri = in.readParcelable(Uri.class.getClassLoader());
-        mUid = in.readInt();
+        mUserHandle = in.readParcelable(UserHandle.class.getClassLoader());
         mPackageName = in.readString();
         mBirthdayText = in.readString();
         mLastInteractionTimestamp = in.readLong();
@@ -375,7 +376,7 @@
         dest.writeCharSequence(mUserName);
         dest.writeParcelable(mUserIcon, flags);
         dest.writeParcelable(mContactUri, flags);
-        dest.writeInt(mUid);
+        dest.writeParcelable(mUserHandle, flags);
         dest.writeString(mPackageName);
         dest.writeString(mBirthdayText);
         dest.writeLong(mLastInteractionTimestamp);
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java
index 73a9cec..94ab0dd 100644
--- a/core/java/android/app/servertransaction/LaunchActivityItem.java
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -71,6 +71,7 @@
     private boolean mIsForward;
     private ProfilerInfo mProfilerInfo;
     private IBinder mAssistToken;
+    private IBinder mShareableActivityToken;
     /**
      * It is only non-null if the process is the first time to launch activity. It is only an
      * optimization for quick look up of the interface so the field is ignored for comparison.
@@ -95,7 +96,7 @@
         ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
                 mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
                 mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
-                client, mAssistToken, mFixedRotationAdjustments);
+                client, mAssistToken, mFixedRotationAdjustments, mShareableActivityToken);
         client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
         Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
     }
@@ -119,7 +120,7 @@
             List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions,
             boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken,
             IActivityClientController activityClientController,
-            FixedRotationAdjustments fixedRotationAdjustments) {
+            FixedRotationAdjustments fixedRotationAdjustments, IBinder shareableActivityToken) {
         LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class);
         if (instance == null) {
             instance = new LaunchActivityItem();
@@ -127,7 +128,7 @@
         setValues(instance, intent, ident, info, curConfig, overrideConfig, compatInfo, referrer,
                 voiceInteractor, procState, state, persistentState, pendingResults,
                 pendingNewIntents, activityOptions, isForward, profilerInfo, assistToken,
-                activityClientController, fixedRotationAdjustments);
+                activityClientController, fixedRotationAdjustments, shareableActivityToken);
 
         return instance;
     }
@@ -135,7 +136,7 @@
     @Override
     public void recycle() {
         setValues(this, null, 0, null, null, null, null, null, null, 0, null, null, null, null,
-                null, false, null, null, null, null);
+                null, false, null, null, null, null, null);
         ObjectPool.recycle(this);
     }
 
@@ -164,6 +165,7 @@
         dest.writeStrongBinder(mAssistToken);
         dest.writeStrongInterface(mActivityClientController);
         dest.writeTypedObject(mFixedRotationAdjustments, flags);
+        dest.writeStrongBinder(mShareableActivityToken);
     }
 
     /** Read from Parcel. */
@@ -181,7 +183,7 @@
                 in.readTypedObject(ProfilerInfo.CREATOR),
                 in.readStrongBinder(),
                 IActivityClientController.Stub.asInterface(in.readStrongBinder()),
-                in.readTypedObject(FixedRotationAdjustments.CREATOR));
+                in.readTypedObject(FixedRotationAdjustments.CREATOR), in.readStrongBinder());
     }
 
     public static final @NonNull Creator<LaunchActivityItem> CREATOR =
@@ -219,7 +221,8 @@
                 && mIsForward == other.mIsForward
                 && Objects.equals(mProfilerInfo, other.mProfilerInfo)
                 && Objects.equals(mAssistToken, other.mAssistToken)
-                && Objects.equals(mFixedRotationAdjustments, other.mFixedRotationAdjustments);
+                && Objects.equals(mFixedRotationAdjustments, other.mFixedRotationAdjustments)
+                && Objects.equals(mShareableActivityToken, other.mShareableActivityToken);
     }
 
     @Override
@@ -241,6 +244,7 @@
         result = 31 * result + Objects.hashCode(mProfilerInfo);
         result = 31 * result + Objects.hashCode(mAssistToken);
         result = 31 * result + Objects.hashCode(mFixedRotationAdjustments);
+        result = 31 * result + Objects.hashCode(mShareableActivityToken);
         return result;
     }
 
@@ -277,7 +281,8 @@
                 + ",persistentState=" + mPersistentState + ",pendingResults=" + mPendingResults
                 + ",pendingNewIntents=" + mPendingNewIntents + ",options=" + mActivityOptions
                 + ",profilerInfo=" + mProfilerInfo + ",assistToken=" + mAssistToken
-                + ",rotationAdj=" + mFixedRotationAdjustments + "}";
+                + ",rotationAdj=" + mFixedRotationAdjustments
+                + ",shareableActivityToken=" + mShareableActivityToken + "}";
     }
 
     // Using the same method to set and clear values to make sure we don't forget anything
@@ -288,7 +293,7 @@
             List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
             ActivityOptions activityOptions, boolean isForward, ProfilerInfo profilerInfo,
             IBinder assistToken, IActivityClientController activityClientController,
-            FixedRotationAdjustments fixedRotationAdjustments) {
+            FixedRotationAdjustments fixedRotationAdjustments, IBinder shareableActivityToken) {
         instance.mIntent = intent;
         instance.mIdent = ident;
         instance.mInfo = info;
@@ -308,5 +313,6 @@
         instance.mAssistToken = assistToken;
         instance.mActivityClientController = activityClientController;
         instance.mFixedRotationAdjustments = fixedRotationAdjustments;
+        instance.mShareableActivityToken = shareableActivityToken;
     }
 }
diff --git a/core/java/android/app/time/LocationTimeZoneManager.java b/core/java/android/app/time/LocationTimeZoneManager.java
index 71a800f..066aada 100644
--- a/core/java/android/app/time/LocationTimeZoneManager.java
+++ b/core/java/android/app/time/LocationTimeZoneManager.java
@@ -37,7 +37,7 @@
     /**
      * The name of the service for shell commands
      */
-    public static final String SHELL_COMMAND_SERVICE_NAME = "location_time_zone_manager";
+    public static final String SERVICE_NAME = "location_time_zone_manager";
 
     /**
      * A shell command that starts the service (after stop).
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index 1d5dc1d..098d8b6 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -16,6 +16,8 @@
 
 package android.app.usage;
 
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -28,8 +30,11 @@
 import android.net.ConnectivityManager;
 import android.net.DataUsageRequest;
 import android.net.INetworkStatsService;
+import android.net.Network;
 import android.net.NetworkStack;
+import android.net.NetworkStateSnapshot;
 import android.net.NetworkTemplate;
+import android.net.UnderlyingNetworkInfo;
 import android.net.netstats.provider.INetworkStatsProviderCallback;
 import android.net.netstats.provider.NetworkStatsProvider;
 import android.os.Binder;
@@ -48,6 +53,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.net.module.util.NetworkIdentityUtils;
 
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -633,6 +639,50 @@
         return template;
     }
 
+    /**
+     *  Notify {@code NetworkStatsService} about network status changed.
+     *
+     *  Notifies NetworkStatsService of network state changes for data usage accounting purposes.
+     *
+     *  To avoid races that attribute data usage to wrong network, such as new network with
+     *  the same interface after SIM hot-swap, this function will not return until
+     *  {@code NetworkStatsService} finishes its work of retrieving traffic statistics from
+     *  all data sources.
+     *
+     * @param defaultNetworks the list of all networks that could be used by network traffic that
+     *                        does not explicitly select a network.
+     * @param networkStateSnapshots a list of {@link NetworkStateSnapshot}s, one for
+     *                              each network that is currently connected.
+     * @param activeIface the active (i.e., connected) default network interface for the calling
+     *                    uid. Used to determine on which network future calls to
+     *                    {@link android.net.TrafficStats#incrementOperationCount} applies to.
+     * @param underlyingNetworkInfos the list of underlying network information for all
+     *                               currently-connected VPNs.
+     *
+     * @hide
+     */
+    @SystemApi(client = MODULE_LIBRARIES)
+    @RequiresPermission(anyOf = {
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+            android.Manifest.permission.NETWORK_STACK})
+    public void notifyNetworkStatus(
+            @NonNull List<Network> defaultNetworks,
+            @NonNull List<NetworkStateSnapshot> networkStateSnapshots,
+            @Nullable String activeIface,
+            @NonNull List<UnderlyingNetworkInfo> underlyingNetworkInfos) {
+        try {
+            Objects.requireNonNull(defaultNetworks);
+            Objects.requireNonNull(networkStateSnapshots);
+            Objects.requireNonNull(underlyingNetworkInfos);
+            // TODO: Change internal namings after the name is decided.
+            mService.forceUpdateIfaces(defaultNetworks.toArray(new Network[0]),
+                    networkStateSnapshots.toArray(new NetworkStateSnapshot[0]), activeIface,
+                    underlyingNetworkInfos.toArray(new UnderlyingNetworkInfo[0]));
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     private static class CallbackHandler extends Handler {
         private final int mNetworkType;
         private final String mSubscriberId;
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 4277292..fc54c71 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -40,6 +40,7 @@
 import android.util.Log;
 import android.util.Pair;
 import android.util.SparseArray;
+import android.util.SparseIntArray;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -92,7 +93,10 @@
     int mLayoutId = -1;
     private InteractionHandler mInteractionHandler;
     private boolean mOnLightBackground;
-    PointF mCurrentSize = null;
+    private PointF mCurrentSize = null;
+    private RemoteViews.ColorResources mColorResources = null;
+    // Stores the last remote views last inflated.
+    private RemoteViews mLastInflatedRemoteViews = null;
 
     private Executor mAsyncExecutor;
     private CancellationSignal mLastExecutionSignal;
@@ -358,7 +362,7 @@
         PointF newSize = new PointF(size.x - xPaddingDips, size.y - yPaddingDips);
         if (!newSize.equals(mCurrentSize)) {
             mCurrentSize = newSize;
-            mLayoutId = -1; // Prevents recycling the view.
+            reapplyLastRemoteViews();
         }
     }
 
@@ -368,7 +372,7 @@
     public void clearCurrentSize() {
         if (mCurrentSize != null) {
             mCurrentSize = null;
-            mLayoutId = -1;
+            reapplyLastRemoteViews();
         }
     }
 
@@ -477,10 +481,18 @@
      * AppWidget provider. Will animate into these new views as needed
      */
     public void updateAppWidget(RemoteViews remoteViews) {
+        this.mLastInflatedRemoteViews = remoteViews;
         applyRemoteViews(remoteViews, true);
     }
 
     /**
+     * Reapply the last inflated remote views, or the default view is none was inflated.
+     */
+    private void reapplyLastRemoteViews() {
+        applyRemoteViews(mLastInflatedRemoteViews, true);
+    }
+
+    /**
      * @hide
      */
     protected void applyRemoteViews(RemoteViews remoteViews, boolean useAsyncIfPossible) {
@@ -518,7 +530,8 @@
             // layout matches, try recycling it
             if (content == null && layoutId == mLayoutId) {
                 try {
-                    remoteViews.reapply(mContext, mView, mInteractionHandler);
+                    remoteViews.reapply(mContext, mView, mInteractionHandler, mCurrentSize,
+                            mColorResources);
                     content = mView;
                     recycled = true;
                     if (LOGD) Log.d(TAG, "was able to recycle existing layout");
@@ -530,7 +543,8 @@
             // Try normal RemoteView inflation
             if (content == null) {
                 try {
-                    content = remoteViews.apply(mContext, this, mInteractionHandler, mCurrentSize);
+                    content = remoteViews.apply(mContext, this, mInteractionHandler,
+                            mCurrentSize, mColorResources);
                     if (LOGD) Log.d(TAG, "had to inflate new layout");
                 } catch (RuntimeException e) {
                     exception = e;
@@ -583,7 +597,8 @@
                         mAsyncExecutor,
                         new ViewApplyListener(remoteViews, layoutId, true),
                         mInteractionHandler,
-                        mCurrentSize);
+                        mCurrentSize,
+                        mColorResources);
             } catch (Exception e) {
                 // Reapply failed. Try apply
             }
@@ -594,7 +609,8 @@
                     mAsyncExecutor,
                     new ViewApplyListener(remoteViews, layoutId, false),
                     mInteractionHandler,
-                    mCurrentSize);
+                    mCurrentSize,
+                    mColorResources);
         }
     }
 
@@ -662,9 +678,13 @@
     protected Context getRemoteContext() {
         try {
             // Return if cloned successfully, otherwise default
-            return mContext.createApplicationContext(
+            Context newContext = mContext.createApplicationContext(
                     mInfo.providerInfo.applicationInfo,
                     Context.CONTEXT_RESTRICTED);
+            if (mColorResources != null) {
+                mColorResources.apply(newContext);
+            }
+            return newContext;
         } catch (NameNotFoundException e) {
             Log.e(TAG, "Package name " +  mInfo.providerInfo.packageName + " not found");
             return mContext;
@@ -819,4 +839,37 @@
             }
         };
     }
+
+    /**
+     * Set the dynamically overloaded color resources.
+     *
+     * {@code colorMapping} maps a predefined set of color resources to their ARGB
+     * representation. Any entry not in the predefined set of colors will be ignored.
+     *
+     * Calling this method will trigger a full re-inflation of the App Widget.
+     *
+     * The color resources that can be overloaded are the ones whose name is prefixed with
+     * {@code system_primary_}, {@code system_secondary_} or {@code system_neutral_}, for example
+     * {@link android.R.color#system_primary_500}.
+     */
+    public void setColorResources(@NonNull SparseIntArray colorMapping) {
+        mColorResources = RemoteViews.ColorResources.create(mContext, colorMapping);
+        mLayoutId = -1;
+        reapplyLastRemoteViews();
+    }
+
+    /**
+     * Reset the dynamically overloaded resources, reverting to the default values for
+     * all the colors.
+     *
+     * If colors were defined before, calling this method will trigger a full re-inflation of the
+     * App Widget.
+     */
+    public void resetColorResources() {
+        if (mColorResources != null) {
+            mColorResources = null;
+            mLayoutId = -1;
+            reapplyLastRemoteViews();
+        }
+    }
 }
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index d893a5e..6ac1c1a 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -332,12 +332,13 @@
 
     /**
      * Resource id for the description of the AppWidget.
+     *
      * <p>This field corresponds to the <code>android:description</code> attribute in the AppWidget
      * meta-data file.
      */
     @SuppressLint("MutableBareField")
     @IdRes
-    public int descriptionResource;
+    public int descriptionRes;
 
     /**
      * Flags indicating various features supported by the widget. These are hints to the widget
@@ -385,7 +386,7 @@
         this.widgetCategory = in.readInt();
         this.providerInfo = in.readTypedObject(ActivityInfo.CREATOR);
         this.widgetFeatures = in.readInt();
-        this.descriptionResource = in.readInt();
+        this.descriptionRes = in.readInt();
     }
 
     /**
@@ -442,14 +443,22 @@
         return loadDrawable(context, density, previewImage, false);
     }
 
-    /** Loads localized description for the app widget. */
+    /**
+     * Loads localized description for the app widget.
+     *
+     * <p>Description is intended to be displayed in the UI of the widget picker.
+     *
+     * @param context Context for accessing resources.
+     *
+     * @return CharSequence for app widget description for the current locale.
+     */
     @Nullable
-    public final String loadDescription(@NonNull Context context) {
-        if (ResourceId.isValid(descriptionResource)) {
+    public final CharSequence loadDescription(@NonNull Context context) {
+        if (ResourceId.isValid(descriptionRes)) {
             return context.getPackageManager()
                     .getText(
                             providerInfo.packageName,
-                            descriptionResource,
+                            descriptionRes,
                             providerInfo.applicationInfo)
                     .toString()
                     .trim();
@@ -499,7 +508,7 @@
         out.writeInt(this.widgetCategory);
         out.writeTypedObject(this.providerInfo, flags);
         out.writeInt(this.widgetFeatures);
-        out.writeInt(this.descriptionResource);
+        out.writeInt(this.descriptionRes);
     }
 
     @Override
@@ -528,7 +537,7 @@
         that.widgetCategory = this.widgetCategory;
         that.providerInfo = this.providerInfo;
         that.widgetFeatures = this.widgetFeatures;
-        that.descriptionResource = this.descriptionResource;
+        that.descriptionRes = this.descriptionRes;
         return that;
     }
 
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index e7661db..ec94faa 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -374,6 +374,35 @@
     public static final String ACTION_SDP_RECORD =
             "android.bluetooth.device.action.SDP_RECORD";
 
+    /** @hide */
+    @IntDef(prefix = "METADATA_", value = {
+            METADATA_MANUFACTURER_NAME,
+            METADATA_MODEL_NAME,
+            METADATA_SOFTWARE_VERSION,
+            METADATA_HARDWARE_VERSION,
+            METADATA_COMPANION_APP,
+            METADATA_MAIN_ICON,
+            METADATA_IS_UNTETHERED_HEADSET,
+            METADATA_UNTETHERED_LEFT_ICON,
+            METADATA_UNTETHERED_RIGHT_ICON,
+            METADATA_UNTETHERED_CASE_ICON,
+            METADATA_UNTETHERED_LEFT_BATTERY,
+            METADATA_UNTETHERED_RIGHT_BATTERY,
+            METADATA_UNTETHERED_CASE_BATTERY,
+            METADATA_UNTETHERED_LEFT_CHARGING,
+            METADATA_UNTETHERED_RIGHT_CHARGING,
+            METADATA_UNTETHERED_CASE_CHARGING,
+            METADATA_ENHANCED_SETTINGS_UI_URI,
+            METADATA_DEVICE_TYPE,
+            METADATA_MAIN_BATTERY,
+            METADATA_MAIN_CHARGING,
+            METADATA_MAIN_LOW_BATTERY_THRESHOLD,
+            METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD,
+            METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD,
+            METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface MetadataKey{}
+
     /**
      * Maximum length of a metadata entry, this is to avoid exploding Bluetooth
      * disk usage
@@ -523,6 +552,89 @@
     public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16;
 
     /**
+     * Type of the Bluetooth device, must be within the list of
+     * BluetoothDevice.DEVICE_TYPE_*
+     * Data type should be {@String} as {@link Byte} array.
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_DEVICE_TYPE = 17;
+
+    /**
+     * Battery level of the Bluetooth device, use when the Bluetooth device
+     * does not support HFP battery indicator.
+     * Data type should be {@String} as {@link Byte} array.
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_MAIN_BATTERY = 18;
+
+    /**
+     * Whether the device is charging.
+     * Data type should be {@String} as {@link Byte} array.
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_MAIN_CHARGING = 19;
+
+    /**
+     * The battery threshold of the Bluetooth device to show low battery icon.
+     * Data type should be {@String} as {@link Byte} array.
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_MAIN_LOW_BATTERY_THRESHOLD = 20;
+
+    /**
+     * The battery threshold of the left headset to show low battery icon.
+     * Data type should be {@String} as {@link Byte} array.
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD = 21;
+
+    /**
+     * The battery threshold of the right headset to show low battery icon.
+     * Data type should be {@String} as {@link Byte} array.
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD = 22;
+
+    /**
+     * The battery threshold of the case to show low battery icon.
+     * Data type should be {@String} as {@link Byte} array.
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD = 23;
+
+    /**
+     * Device type which is used in METADATA_DEVICE_TYPE
+     * Indicates this Bluetooth device is a standard Bluetooth accessory or
+     * not listed in METADATA_DEVICE_TYPE_*.
+     * @hide
+     */
+    @SystemApi
+    public static final String DEVICE_TYPE_DEFAULT = "Default";
+
+    /**
+     * Device type which is used in METADATA_DEVICE_TYPE
+     * Indicates this Bluetooth device is a watch.
+     * @hide
+     */
+    @SystemApi
+    public static final String DEVICE_TYPE_WATCH = "Watch";
+
+    /**
+     * Device type which is used in METADATA_DEVICE_TYPE
+     * Indicates this Bluetooth device is an untethered headset.
+     * @hide
+     */
+    @SystemApi
+    public static final String DEVICE_TYPE_UNTETHERED_HEADSET = "Untethered Headset";
+
+    /**
      * Broadcast Action: This intent is used to broadcast the {@link UUID}
      * wrapped as a {@link android.os.ParcelUuid} of the remote device after it
      * has been fetched. This intent is sent only when the UUIDs of the remote
@@ -2316,7 +2428,7 @@
     */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
-    public boolean setMetadata(int key, @NonNull byte[] value) {
+    public boolean setMetadata(@MetadataKey int key, @NonNull byte[] value) {
         final IBluetooth service = sService;
         if (service == null) {
             Log.e(TAG, "Bluetooth is not enabled. Cannot set metadata");
@@ -2344,7 +2456,7 @@
     @SystemApi
     @Nullable
     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
-    public byte[] getMetadata(int key) {
+    public byte[] getMetadata(@MetadataKey int key) {
         final IBluetooth service = sService;
         if (service == null) {
             Log.e(TAG, "Bluetooth is not enabled. Cannot get metadata");
@@ -2357,4 +2469,14 @@
             return null;
         }
     }
+
+    /**
+     * Get the maxinum metadata key ID.
+     *
+     * @return the last supported metadata key
+     * @hide
+     */
+    public static @MetadataKey int getMaxMetadataKey() {
+        return METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD;
+    }
 }
diff --git a/core/java/android/bluetooth/le/PeriodicAdvertisingParameters.java b/core/java/android/bluetooth/le/PeriodicAdvertisingParameters.java
index e3a130c..4e64dbe 100644
--- a/core/java/android/bluetooth/le/PeriodicAdvertisingParameters.java
+++ b/core/java/android/bluetooth/le/PeriodicAdvertisingParameters.java
@@ -22,7 +22,7 @@
 /**
  * The {@link PeriodicAdvertisingParameters} provide a way to adjust periodic
  * advertising preferences for each Bluetooth LE advertising set. Use {@link
- * AdvertisingSetParameters.Builder} to create an instance of this class.
+ * PeriodicAdvertisingParameters.Builder} to create an instance of this class.
  */
 public final class PeriodicAdvertisingParameters implements Parcelable {
 
diff --git a/core/java/android/companion/DeviceNotAssociatedException.java b/core/java/android/companion/DeviceNotAssociatedException.java
index bebb6c9..f8a7a7c 100644
--- a/core/java/android/companion/DeviceNotAssociatedException.java
+++ b/core/java/android/companion/DeviceNotAssociatedException.java
@@ -23,7 +23,7 @@
  * An exception for a case when a given device was not
  * {@link CompanionDeviceManager#associate associated} to the calling app.
  */
-public class DeviceNotAssociatedException extends Exception {
+public class DeviceNotAssociatedException extends RuntimeException {
     /** @hide */
     public DeviceNotAssociatedException(@Nullable String deviceName) {
         super("Device not associated with the current app: " + deviceName);
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 46d8900..230c985 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -132,8 +132,11 @@
     public static final String SYNC_EXTRAS_ACCOUNT = "account";
 
     /**
-     * If this extra is set to true, the sync request will be scheduled
-     * at the front of the sync request queue and without any delay
+     * If this extra is set to true, the sync request will be scheduled at the front of the
+     * sync request queue, but it is still subject to JobScheduler quota and throttling due to
+     * App Standby buckets.
+     *
+     * <p>This is different from {@link #SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB}.
      */
     public static final String SYNC_EXTRAS_EXPEDITED = "expedited";
 
@@ -145,6 +148,29 @@
     public static final String SYNC_EXTRAS_REQUIRE_CHARGING = "require_charging";
 
     /**
+     * Run this sync operation as an "expedited job"
+     * (see {@link android.app.job.JobInfo.Builder#setExpedited(boolean)}).
+     * Normally (if this flag isn't specified), sync operations are executed as regular
+     * {@link android.app.job.JobService} jobs.
+     *
+     * <p> Because Expedited Jobs have various restrictions compared to regular jobs, this flag
+     * cannot be combined with certain other flags, otherwise an
+     * <code>IllegalArgumentException</code> will be thrown. Notably, because Expedited Jobs do not
+     * support various constraints, the following restriction apply:
+     * <ul>
+     *  <li>Can't be used with {@link #SYNC_EXTRAS_REQUIRE_CHARGING}
+     *  <li>Can't be used with {@link #SYNC_EXTRAS_EXPEDITED}
+     *  <li>Can't be used on periodic syncs.
+     *  <li>When an expedited-job-sync fails and a retry is scheduled, the retried sync will be
+     *  scheduled as a regular job unless {@link #SYNC_EXTRAS_IGNORE_BACKOFF} is set.
+     * </ul>
+     *
+     * <p>This is different from {@link #SYNC_EXTRAS_EXPEDITED}.
+     */
+    @SuppressLint("IntentName")
+    public static final String SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB = "schedule_as_expedited_job";
+
+    /**
      * @deprecated instead use
      * {@link #SYNC_EXTRAS_MANUAL}
      */
@@ -3220,6 +3246,18 @@
     }
 
     /**
+     * {@hide}
+     * Helper function to throw an <code>IllegalArgumentException</code> if any illegal
+     * extras were set for a sync scheduled as an expedited job.
+     *
+     * @param extras bundle to validate.
+     */
+    public static boolean hasInvalidScheduleAsEjExtras(Bundle extras) {
+        return extras.getBoolean(ContentResolver.SYNC_EXTRAS_REQUIRE_CHARGING)
+                || extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED);
+    }
+
+    /**
      * Specifies that a sync should be requested with the specified the account, authority,
      * and extras at the given frequency. If there is already another periodic sync scheduled
      * with the account, authority and extras then a new periodic sync won't be added, instead
@@ -3233,7 +3271,8 @@
      * Periodic syncs are not allowed to have any of {@link #SYNC_EXTRAS_DO_NOT_RETRY},
      * {@link #SYNC_EXTRAS_IGNORE_BACKOFF}, {@link #SYNC_EXTRAS_IGNORE_SETTINGS},
      * {@link #SYNC_EXTRAS_INITIALIZE}, {@link #SYNC_EXTRAS_FORCE},
-     * {@link #SYNC_EXTRAS_EXPEDITED}, {@link #SYNC_EXTRAS_MANUAL} set to true.
+     * {@link #SYNC_EXTRAS_EXPEDITED}, {@link #SYNC_EXTRAS_MANUAL},
+     * {@link #SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB} set to true.
      * If any are supplied then an {@link IllegalArgumentException} will be thrown.
      *
      * <p>This method requires the caller to hold the permission
@@ -3273,16 +3312,14 @@
      * @param extras bundle to validate.
      */
     public static boolean invalidPeriodicExtras(Bundle extras) {
-        if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)
+        return extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)
                 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false)
                 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false)
                 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false)
                 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)
                 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false)
-                || extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)) {
-            return true;
-        }
-        return false;
+                || extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)
+                || extras.getBoolean(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, false);
     }
 
     /**
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index e20f706..f3a4e1f 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -370,6 +370,25 @@
     /***********    Hidden flags below this line ***********/
 
     /**
+     * Flag for {@link #bindService}: allow the process hosting the target service to be treated
+     * as if it's as important as a perceptible app to the user and avoid the oom killer killing
+     * this process in low memory situations until there aren't any other processes left but the
+     * ones which are user-perceptible.
+     *
+     * @hide
+     */
+    public static final int BIND_ALMOST_PERCEPTIBLE = 0x000010000;
+
+    /**
+     * Flag for {@link #bindService}: allow the process hosting the target service to gain
+     * {@link ActivityManager#PROCESS_CAPABILITY_NETWORK}, which allows it be able
+     * to access network regardless of any power saving restrictions.
+     *
+     * @hide
+     */
+    public static final int BIND_ALLOW_NETWORK_ACCESS = 0x00020000;
+
+    /**
      * Flag for {@link #bindService}: allow background foreground service starts from the bound
      * service's process.
      * This flag is only respected if the caller is holding
@@ -6674,15 +6693,6 @@
     }
 
     /**
-     * Indicates if this context is a visual context such as {@link android.app.Activity} or
-     * a context created from {@link #createWindowContext(int, Bundle)}.
-     * @hide
-     */
-    public boolean isUiContext() {
-        throw new RuntimeException("Not implemented. Must override in a subclass.");
-    }
-
-    /**
      * Returns {@code true} if the context is a UI context which can access UI components such as
      * {@link WindowManager}, {@link android.view.LayoutInflater LayoutInflater} or
      * {@link android.app.WallpaperManager WallpaperManager}. Accessing UI components from non-UI
@@ -6694,12 +6704,16 @@
      * {@link #createWindowContext(int, Bundle)} or
      * {@link android.inputmethodservice.InputMethodService InputMethodService}
      * </p>
+     * <p>
+     * Note that even if it is allowed programmatically, it is not suggested to override this
+     * method to bypass {@link android.os.strictmode.IncorrectContextUseViolation} verification.
+     * </p>
      *
      * @see #getDisplay()
      * @see #getSystemService(String)
      * @see android.os.StrictMode.VmPolicy.Builder#detectIncorrectContextUse()
      */
-    public static boolean isUiContext(@NonNull Context context) {
-        return context.isUiContext();
+    public boolean isUiContext() {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
     }
 }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d53d20a..d352b27 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -6755,6 +6755,12 @@
      */
     private static final int LOCAL_FLAG_FROM_PROTECTED_COMPONENT = 1 << 2;
 
+    /**
+     * Local flag indicating this instance had unfiltered extras copied into it. This could be
+     * from either {@link #putExtras(Intent)} when an unparceled Intent is provided or {@link
+     * #putExtras(Bundle)} when the provided Bundle has not been unparceled.
+     */
+    private static final int LOCAL_FLAG_UNFILTERED_EXTRAS = 1 << 3;
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // toUri() and parseUri() options.
@@ -10009,6 +10015,15 @@
                 mExtras.putAll(src.mExtras);
             }
         }
+        // If the provided Intent was unparceled and this is not an Intent delivered to a protected
+        // component then mark the extras as unfiltered. An Intent delivered to a protected
+        // component had to come from a trusted component, and if unfiltered data was copied to the
+        // delivered Intent then it would have been reported when that Intent left the sending
+        // process.
+        if ((src.mLocalFlags & LOCAL_FLAG_FROM_PARCEL) != 0
+                && (src.mLocalFlags & LOCAL_FLAG_FROM_PROTECTED_COMPONENT) == 0) {
+            mLocalFlags |= LOCAL_FLAG_UNFILTERED_EXTRAS;
+        }
         return this;
     }
 
@@ -10023,6 +10038,10 @@
      * @see #removeExtra
      */
     public @NonNull Intent putExtras(@NonNull Bundle extras) {
+        // If the provided Bundle has not yet been unparceled then treat this as unfiltered extras.
+        if (extras.isParcelled()) {
+            mLocalFlags |= LOCAL_FLAG_UNFILTERED_EXTRAS;
+        }
         if (mExtras == null) {
             mExtras = new Bundle();
         }
@@ -11328,10 +11347,13 @@
         }
 
         // Detect cases where we're about to launch a potentially unsafe intent
-        if ((mLocalFlags & LOCAL_FLAG_FROM_PARCEL) != 0
-                && (mLocalFlags & LOCAL_FLAG_FROM_PROTECTED_COMPONENT) == 0
-                && StrictMode.vmUnsafeIntentLaunchEnabled()) {
-            StrictMode.onUnsafeIntentLaunch(this);
+        if (StrictMode.vmUnsafeIntentLaunchEnabled()) {
+            if ((mLocalFlags & LOCAL_FLAG_FROM_PARCEL) != 0
+                    && (mLocalFlags & LOCAL_FLAG_FROM_PROTECTED_COMPONENT) == 0) {
+                StrictMode.onUnsafeIntentLaunch(this);
+            } else if ((mLocalFlags & LOCAL_FLAG_UNFILTERED_EXTRAS) != 0) {
+                StrictMode.onUnsafeIntentLaunch(this);
+            }
         }
     }
 
diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java
index 858d1e4..b1252fd 100644
--- a/core/java/android/content/IntentSender.java
+++ b/core/java/android/content/IntentSender.java
@@ -18,6 +18,7 @@
 
 import android.annotation.Nullable;
 import android.app.ActivityManager;
+import android.app.ActivityManager.PendingIntentInfo;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Bundle;
 import android.os.Handler;
@@ -60,6 +61,9 @@
     private final IIntentSender mTarget;
     IBinder mWhitelistToken;
 
+    // cached pending intent information
+    private @Nullable PendingIntentInfo mCachedInfo;
+
     /**
      * Exception thrown when trying to send through a PendingIntent that
      * has been canceled or is otherwise no longer able to execute the request.
@@ -209,13 +213,7 @@
      */
     @Deprecated
     public String getTargetPackage() {
-        try {
-            return ActivityManager.getService()
-                .getPackageForIntentSender(mTarget);
-        } catch (RemoteException e) {
-            // Should never happen.
-            return null;
-        }
+        return getCreatorPackage();
     }
 
     /**
@@ -228,13 +226,7 @@
      * none associated with it.
      */
     public String getCreatorPackage() {
-        try {
-            return ActivityManager.getService()
-                .getPackageForIntentSender(mTarget);
-        } catch (RemoteException e) {
-            // Should never happen.
-            return null;
-        }
+        return getCachedInfo().getCreatorPackage();
     }
 
     /**
@@ -247,13 +239,7 @@
      * none associated with it.
      */
     public int getCreatorUid() {
-        try {
-            return ActivityManager.getService()
-                .getUidForIntentSender(mTarget);
-        } catch (RemoteException e) {
-            // Should never happen.
-            return -1;
-        }
+        return getCachedInfo().getCreatorUid();
     }
 
     /**
@@ -268,14 +254,8 @@
      * none associated with it.
      */
     public UserHandle getCreatorUserHandle() {
-        try {
-            int uid = ActivityManager.getService()
-                .getUidForIntentSender(mTarget);
-            return uid > 0 ? new UserHandle(UserHandle.getUserId(uid)) : null;
-        } catch (RemoteException e) {
-            // Should never happen.
-            return null;
-        }
+        int uid = getCachedInfo().getCreatorUid();
+        return uid > 0 ? new UserHandle(UserHandle.getUserId(uid)) : null;
     }
 
     /**
@@ -384,4 +364,16 @@
     public IntentSender(IBinder target) {
         mTarget = IIntentSender.Stub.asInterface(target);
     }
+
+    private PendingIntentInfo getCachedInfo() {
+        if (mCachedInfo == null) {
+            try {
+                mCachedInfo = ActivityManager.getService().getInfoForIntentSender(mTarget);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        return mCachedInfo;
+    }
 }
diff --git a/core/java/android/content/SyncRequest.java b/core/java/android/content/SyncRequest.java
index 9e568a4..e1e6f75 100644
--- a/core/java/android/content/SyncRequest.java
+++ b/core/java/android/content/SyncRequest.java
@@ -17,6 +17,7 @@
 package android.content;
 
 import android.accounts.Account;
+import android.annotation.NonNull;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Bundle;
@@ -58,6 +59,8 @@
     private final boolean mIsAuthority;
     /** Sync should be run in lieu of other syncs. */
     private final boolean mIsExpedited;
+    /** Sync sound be ran as an expedited job. */
+    private final boolean mIsScheduledAsExpeditedJob;
 
     /**
      * {@hide}
@@ -79,6 +82,14 @@
 
     /**
      * {@hide}
+     * @return whether this sync is scheduled as an expedited job.
+     */
+    public boolean isScheduledAsExpeditedJob() {
+        return mIsScheduledAsExpeditedJob;
+    }
+
+    /**
+     * {@hide}
      *
      * @return account object for this sync.
      * @throws IllegalArgumentException if this function is called for a request that targets a
@@ -149,6 +160,7 @@
         parcel.writeInt((mDisallowMetered ? 1 : 0));
         parcel.writeInt((mIsAuthority ? 1 : 0));
         parcel.writeInt((mIsExpedited? 1 : 0));
+        parcel.writeInt(mIsScheduledAsExpeditedJob ? 1 : 0);
         parcel.writeParcelable(mAccountToSync, flags);
         parcel.writeString(mAuthority);
     }
@@ -161,6 +173,7 @@
         mDisallowMetered = (in.readInt() != 0);
         mIsAuthority = (in.readInt() != 0);
         mIsExpedited = (in.readInt() != 0);
+        mIsScheduledAsExpeditedJob = (in.readInt() != 0);
         mAccountToSync = in.readParcelable(null);
         mAuthority = in.readString();
     }
@@ -174,6 +187,7 @@
         mIsPeriodic = (b.mSyncType == Builder.SYNC_TYPE_PERIODIC);
         mIsAuthority = (b.mSyncTarget == Builder.SYNC_TARGET_ADAPTER);
         mIsExpedited = b.mExpedited;
+        mIsScheduledAsExpeditedJob = b.mScheduleAsExpeditedJob;
         mExtras = new Bundle(b.mCustomExtras);
         // For now we merge the sync config extras & the custom extras into one bundle.
         // TODO: pass the configuration extras through separately.
@@ -258,6 +272,11 @@
          */
         private boolean mRequiresCharging;
 
+        /**
+         * Whether the sync should be scheduled as an expedited job.
+         */
+        private boolean mScheduleAsExpeditedJob;
+
         public Builder() {
         }
 
@@ -309,7 +328,8 @@
          * {@link ContentResolver#SYNC_EXTRAS_INITIALIZE},
          * {@link ContentResolver#SYNC_EXTRAS_FORCE},
          * {@link ContentResolver#SYNC_EXTRAS_EXPEDITED},
-         * {@link ContentResolver#SYNC_EXTRAS_MANUAL}
+         * {@link ContentResolver#SYNC_EXTRAS_MANUAL},
+         * {@link ContentResolver#SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB}
          * set to true. If any are supplied then an <code>IllegalArgumentException</code> will
          * be thrown.
          *
@@ -500,6 +520,22 @@
         }
 
         /**
+         * Convenience function for setting
+         * {@link ContentResolver#SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB}.
+         *
+         * <p> Not to be confused with {@link ContentResolver#SYNC_EXTRAS_EXPEDITED}.
+         *
+         * <p> Not valid for periodic syncs, expedited syncs, and syncs that require charging - an
+         * <code>IllegalArgumentException</code> will be thrown in {@link #build()}.
+         *
+         * @param scheduleAsExpeditedJob whether to schedule as an expedited job. Default false.
+         */
+        public @NonNull Builder setScheduleAsExpeditedJob(boolean scheduleAsExpeditedJob) {
+            mScheduleAsExpeditedJob = scheduleAsExpeditedJob;
+            return this;
+        }
+
+        /**
          * Performs validation over the request and throws the runtime exception
          * <code>IllegalArgumentException</code> if this validation fails.
          *
@@ -507,11 +543,6 @@
          *         builder.
          */
         public SyncRequest build() {
-            // Validate the extras bundle
-            ContentResolver.validateSyncExtrasBundle(mCustomExtras);
-            if (mCustomExtras == null) {
-                mCustomExtras = new Bundle();
-            }
             // Combine builder extra flags into the config bundle.
             mSyncConfigExtras = new Bundle();
             if (mIgnoreBackoff) {
@@ -532,17 +563,35 @@
             if (mExpedited) {
                 mSyncConfigExtras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
             }
+            if (mScheduleAsExpeditedJob) {
+                mSyncConfigExtras.putBoolean(
+                        ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, true);
+            }
             if (mIsManual) {
                 mSyncConfigExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true);
                 mSyncConfigExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);
             }
+
+            if (mCustomExtras == null) {
+                mCustomExtras = new Bundle();
+            }
+            // Validate the extras bundles
+            ContentResolver.validateSyncExtrasBundle(mCustomExtras);
+            // If this is a periodic sync ensure than invalid extras were not set.
             if (mSyncType == SYNC_TYPE_PERIODIC) {
-                // If this is a periodic sync ensure than invalid extras were not set.
                 if (ContentResolver.invalidPeriodicExtras(mCustomExtras) ||
                         ContentResolver.invalidPeriodicExtras(mSyncConfigExtras)) {
                     throw new IllegalArgumentException("Illegal extras were set");
                 }
             }
+            // If this sync is scheduled as an EJ, ensure that invalid extras were not set.
+            if (mCustomExtras.getBoolean(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB)
+                    || mScheduleAsExpeditedJob) {
+                if (ContentResolver.hasInvalidScheduleAsEjExtras(mCustomExtras)
+                        || ContentResolver.hasInvalidScheduleAsEjExtras(mSyncConfigExtras)) {
+                    throw new IllegalArgumentException("Illegal extras were set");
+                }
+            }
             // Ensure that a target for the sync has been set.
             if (mSyncTarget == SYNC_TARGET_UNKNOWN) {
                 throw new IllegalArgumentException("Must specify an adapter with" +
diff --git a/core/java/android/content/pm/AppSearchPerson.java b/core/java/android/content/pm/AppSearchPerson.java
index d70ac91..66295eb 100644
--- a/core/java/android/content/pm/AppSearchPerson.java
+++ b/core/java/android/content/pm/AppSearchPerson.java
@@ -42,7 +42,7 @@
     public static final String KEY_IS_BOT = "isBot";
     public static final String KEY_IS_IMPORTANT = "isImportant";
 
-    private AppSearchPerson(@NonNull GenericDocument document) {
+    public AppSearchPerson(@NonNull GenericDocument document) {
         super(document);
     }
 
diff --git a/core/java/android/content/pm/AppSearchShortcutInfo.java b/core/java/android/content/pm/AppSearchShortcutInfo.java
index ebe202b..5af3b5a 100644
--- a/core/java/android/content/pm/AppSearchShortcutInfo.java
+++ b/core/java/android/content/pm/AppSearchShortcutInfo.java
@@ -28,7 +28,6 @@
 import android.graphics.drawable.Icon;
 import android.os.Bundle;
 import android.os.PersistableBundle;
-import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.ArraySet;
 
@@ -53,17 +52,23 @@
     /** The name of the schema type for {@link ShortcutInfo} documents.*/
     public static final String SCHEMA_TYPE = "Shortcut";
 
-    public static final String KEY_PACKAGE_NAME = "packageName";
     public static final String KEY_ACTIVITY = "activity";
-    public static final String KEY_TITLE = "title";
-    public static final String KEY_TEXT = "text";
+    public static final String KEY_SHORT_LABEL = "shortLabel";
+    public static final String KEY_SHORT_LABEL_RES_ID = "shortLabelResId";
+    public static final String KEY_SHORT_LABEL_RES_NAME = "shortLabelResName";
+    public static final String KEY_LONG_LABEL = "longLabel";
+    public static final String KEY_LONG_LABEL_RES_ID = "longLabelResId";
+    public static final String KEY_LONG_LABEL_RES_NAME = "longLabelResName";
     public static final String KEY_DISABLED_MESSAGE = "disabledMessage";
+    public static final String KEY_DISABLED_MESSAGE_RES_ID = "disabledMessageResId";
+    public static final String KEY_DISABLED_MESSAGE_RES_NAME = "disabledMessageResName";
     public static final String KEY_CATEGORIES = "categories";
     public static final String KEY_INTENTS = "intents";
     public static final String KEY_INTENT_PERSISTABLE_EXTRAS = "intentPersistableExtras";
     public static final String KEY_PERSON = "person";
     public static final String KEY_LOCUS_ID = "locusId";
     public static final String KEY_RANK = "rank";
+    public static final String KEY_IMPLICIT_RANK = "implicitRank";
     public static final String KEY_EXTRAS = "extras";
     public static final String KEY_FLAGS = "flags";
     public static final String KEY_ICON_RES_ID = "iconResId";
@@ -73,36 +78,62 @@
     public static final String KEY_DISABLED_REASON = "disabledReason";
 
     public static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
-            .addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_PACKAGE_NAME)
-                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
-                    .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
-                    .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
-                    .build()
-
-            ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_ACTIVITY)
+            .addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_ACTIVITY)
                     .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
                     .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
                     .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
                     .build()
 
-            ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_TITLE)
+            ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_SHORT_LABEL)
                     .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
                     .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
                     .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
                     .build()
 
-            ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_TEXT)
+            ).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(KEY_SHORT_LABEL_RES_ID)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_SHORT_LABEL_RES_NAME)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+                    .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_LONG_LABEL)
                     .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
                     .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
                     .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
                     .build()
 
+            ).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(KEY_LONG_LABEL_RES_ID)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_LONG_LABEL_RES_NAME)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+                    .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+                    .build()
+
             ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_DISABLED_MESSAGE)
                     .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
                     .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
                     .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
                     .build()
 
+            ).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(
+                    KEY_DISABLED_MESSAGE_RES_ID)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .build()
+
+            ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(
+                    KEY_DISABLED_MESSAGE_RES_NAME)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
+                    .setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
+                    .build()
+
             ).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_CATEGORIES)
                     .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
                     .setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
@@ -135,6 +166,10 @@
                     .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
                     .build()
 
+            ).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(KEY_IMPLICIT_RANK)
+                    .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                    .build()
+
             ).addProperty(new AppSearchSchema.BytesPropertyConfig.Builder(KEY_EXTRAS)
                     .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
                     .build()
@@ -183,13 +218,21 @@
         Objects.requireNonNull(shortcutInfo);
         return new Builder(shortcutInfo.getId())
                 .setActivity(shortcutInfo.getActivity())
-                .setPackageName(shortcutInfo.getPackage())
-                .setTitle(shortcutInfo.getShortLabel())
-                .setText(shortcutInfo.getLongLabel())
+                .setNamespace(shortcutInfo.getPackage())
+                .setShortLabel(shortcutInfo.getShortLabel())
+                .setShortLabelResId(shortcutInfo.getShortLabelResourceId())
+                .setShortLabelResName(shortcutInfo.getTitleResName())
+                .setLongLabel(shortcutInfo.getLongLabel())
+                .setLongLabelResId(shortcutInfo.getLongLabelResourceId())
+                .setLongLabelResName(shortcutInfo.getTextResName())
                 .setDisabledMessage(shortcutInfo.getDisabledMessage())
+                .setDisabledMessageResId(shortcutInfo.getDisabledMessageResourceId())
+                .setDisabledMessageResName(shortcutInfo.getDisabledMessageResName())
                 .setCategories(shortcutInfo.getCategories())
                 .setIntents(shortcutInfo.getIntents())
                 .setRank(shortcutInfo.getRank())
+                .setImplicitRank(shortcutInfo.getImplicitRank()
+                        | (shortcutInfo.isRankChanged() ? ShortcutInfo.RANK_CHANGED_BIT : 0))
                 .setExtras(shortcutInfo.getExtras())
                 .setCreationTimestampMillis(shortcutInfo.getLastChangedTimestamp())
                 .setFlags(shortcutInfo.getFlags())
@@ -207,17 +250,8 @@
      * @hide
      */
     @NonNull
-    public ShortcutInfo toShortcutInfo() {
-        return toShortcutInfo(UserHandle.myUserId());
-    }
-
-    /**
-     * @hide
-     * TODO: This should be @SystemApi when AppSearchShortcutInfo unhides.
-     */
-    @NonNull
-    public ShortcutInfo toShortcutInfo(@UserIdInt final int userId) {
-        final String packageName = getPropertyString(KEY_PACKAGE_NAME);
+    public ShortcutInfo toShortcutInfo(@UserIdInt int userId) {
+        final String packageName = getNamespace();
         final String activityString = getPropertyString(KEY_ACTIVITY);
         final ComponentName activity = activityString == null
                 ? null : ComponentName.unflattenFromString(activityString);
@@ -228,15 +262,24 @@
         // @hide and @UnsupportedAppUsage, we could migrate existing usage in platform with
         // LauncherApps#getShortcutIconDrawable instead.
         final Icon icon = null;
-        final String title = getPropertyString(KEY_TITLE);
-        final String text = getPropertyString(KEY_TEXT);
+        final String shortLabel = getPropertyString(KEY_SHORT_LABEL);
+        final int shortLabelResId = (int) getPropertyLong(KEY_SHORT_LABEL_RES_ID);
+        final String shortLabelResName = getPropertyString(KEY_SHORT_LABEL_RES_NAME);
+        final String longLabel = getPropertyString(KEY_LONG_LABEL);
+        final int longLabelResId = (int) getPropertyLong(KEY_LONG_LABEL_RES_ID);
+        final String longLabelResName = getPropertyString(KEY_LONG_LABEL_RES_NAME);
         final String disabledMessage = getPropertyString(KEY_DISABLED_MESSAGE);
+        final int disabledMessageResId = (int) getPropertyLong(KEY_DISABLED_MESSAGE_RES_ID);
+        final String disabledMessageResName = getPropertyString(KEY_DISABLED_MESSAGE_RES_NAME);
         final String[] categories = getPropertyStringArray(KEY_CATEGORIES);
         final Set<String> categoriesSet = categories == null
-                ? new ArraySet<>() : new ArraySet<>(Arrays.asList(categories));
+                ? null : new ArraySet<>(Arrays.asList(categories));
         final String[] intentsStrings = getPropertyStringArray(KEY_INTENTS);
         final Intent[] intents = intentsStrings == null
-                ? null : Arrays.stream(intentsStrings).map(uri -> {
+                ? new Intent[0] : Arrays.stream(intentsStrings).map(uri -> {
+                    if (TextUtils.isEmpty(uri)) {
+                        return new Intent(Intent.ACTION_VIEW);
+                    }
                     try {
                         return Intent.parseUri(uri, /* flags =*/ 0);
                     } catch (URISyntaxException e) {
@@ -251,15 +294,18 @@
         if (intents != null) {
             for (int i = 0; i < intents.length; i++) {
                 final Intent intent = intents[i];
-                if (intent != null) {
-                    intent.replaceExtras(intentExtrases[i].size() == 0 ? null : intentExtrases[i]);
+                if (intent == null || intentExtrases == null || intentExtrases.length <= i
+                        || intentExtrases[i] == null || intentExtrases[i].size() == 0) {
+                    continue;
                 }
+                intent.replaceExtras(intentExtrases[i]);
             }
         }
         final Person[] persons = parsePerson(getPropertyDocumentArray(KEY_PERSON));
         final String locusIdString = getPropertyString(KEY_LOCUS_ID);
         final LocusId locusId = locusIdString == null ? null : new LocusId(locusIdString);
         final int rank = (int) getPropertyLong(KEY_RANK);
+        final int implicitRank = (int) getPropertyLong(KEY_IMPLICIT_RANK);
         final byte[] extrasByte = getPropertyBytes(KEY_EXTRAS);
         final PersistableBundle extras = transformToPersistableBundle(extrasByte);
         final int flags = parseFlags(getPropertyLongArray(KEY_FLAGS));
@@ -268,12 +314,17 @@
         final String iconUri = getPropertyString(KEY_ICON_URI);
         final String bitmapPath = getPropertyString(KEY_BITMAP_PATH);
         final int disabledReason = (int) getPropertyLong(KEY_DISABLED_REASON);
-        return new ShortcutInfo(
-                userId, getUri(), packageName, activity, icon, title, 0, null,
-                text, 0, null, disabledMessage, 0, null,
-                categoriesSet, intents, rank, extras,
+        final ShortcutInfo si = new ShortcutInfo(
+                userId, getUri(), packageName, activity, icon, shortLabel, shortLabelResId,
+                shortLabelResName, longLabel, longLabelResId, longLabelResName, disabledMessage,
+                disabledMessageResId, disabledMessageResName, categoriesSet, intents, rank, extras,
                 getCreationTimestampMillis(), flags, iconResId, iconResName, bitmapPath, iconUri,
                 disabledReason, persons, locusId, 0);
+        si.setImplicitRank(implicitRank);
+        if ((implicitRank & ShortcutInfo.RANK_CHANGED_BIT) != 0) {
+            si.setRankChanged();
+        }
+        return si;
     }
 
     /** @hide */
@@ -310,9 +361,9 @@
          * @hide
          */
         @NonNull
-        public Builder setTitle(@Nullable final CharSequence shortLabel) {
+        public Builder setShortLabel(@Nullable final CharSequence shortLabel) {
             if (!TextUtils.isEmpty(shortLabel)) {
-                setPropertyString(KEY_TITLE, Preconditions.checkStringNotEmpty(
+                setPropertyString(KEY_SHORT_LABEL, Preconditions.checkStringNotEmpty(
                         shortLabel, "shortLabel cannot be empty").toString());
             }
             return this;
@@ -322,13 +373,50 @@
          * @hide
          */
         @NonNull
-        public Builder setText(@Nullable final CharSequence longLabel) {
+        public Builder setShortLabelResId(@Nullable final int shortLabelResId) {
+            setPropertyLong(KEY_SHORT_LABEL_RES_ID, shortLabelResId);
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        public Builder setShortLabelResName(@Nullable final String shortLabelResName) {
+            if (!TextUtils.isEmpty(shortLabelResName)) {
+                setPropertyString(KEY_SHORT_LABEL_RES_NAME, shortLabelResName);
+            }
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        @NonNull
+        public Builder setLongLabel(@Nullable final CharSequence longLabel) {
             if (!TextUtils.isEmpty(longLabel)) {
-                setPropertyString(KEY_TEXT, Preconditions.checkStringNotEmpty(
+                setPropertyString(KEY_LONG_LABEL, Preconditions.checkStringNotEmpty(
                         longLabel, "longLabel cannot be empty").toString());
             }
             return this;
+        }
 
+        /**
+         * @hide
+         */
+        @NonNull
+        public Builder setLongLabelResId(@Nullable final int longLabelResId) {
+            setPropertyLong(KEY_LONG_LABEL_RES_ID, longLabelResId);
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        public Builder setLongLabelResName(@Nullable final String longLabelResName) {
+            if (!TextUtils.isEmpty(longLabelResName)) {
+                setPropertyString(KEY_LONG_LABEL_RES_NAME, longLabelResName);
+            }
+            return this;
         }
 
         /**
@@ -347,6 +435,25 @@
          * @hide
          */
         @NonNull
+        public Builder setDisabledMessageResId(@Nullable final int disabledMessageResId) {
+            setPropertyLong(KEY_DISABLED_MESSAGE_RES_ID, disabledMessageResId);
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        public Builder setDisabledMessageResName(@Nullable final String disabledMessageResName) {
+            if (!TextUtils.isEmpty(disabledMessageResName)) {
+                setPropertyString(KEY_DISABLED_MESSAGE_RES_NAME, disabledMessageResName);
+            }
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        @NonNull
         public Builder setCategories(@Nullable final Set<String> categories) {
             if (categories != null && !categories.isEmpty()) {
                 setPropertyString(KEY_CATEGORIES, categories.stream().toArray(String[]::new));
@@ -384,9 +491,8 @@
                 intentExtrases[i] = extras == null
                         ? new byte[0] : transformToByteArray(new PersistableBundle(extras));
             }
-
-            setPropertyString(KEY_INTENTS, Arrays.stream(intents).map(it ->
-                    it.toUri(0)).toArray(String[]::new));
+            setPropertyString(KEY_INTENTS, Arrays.stream(intents).map(it -> it.toUri(0))
+                    .toArray(String[]::new));
             setPropertyBytes(KEY_INTENT_PERSISTABLE_EXTRAS, intentExtrases);
             return this;
         }
@@ -410,10 +516,14 @@
             if (persons == null || persons.length == 0) {
                 return this;
             }
-            setPropertyDocument(KEY_PERSON,
-                    Arrays.stream(persons).map(person -> AppSearchPerson.instance(
-                            Objects.requireNonNull(person, "persons cannot contain null"))
-                    ).toArray(AppSearchPerson[]::new));
+            final GenericDocument[] documents = new GenericDocument[persons.length];
+            for (int i = 0; i < persons.length; i++) {
+                final Person person = persons[i];
+                if (person == null) continue;
+                final AppSearchPerson appSearchPerson = AppSearchPerson.instance(person);
+                documents[i] = appSearchPerson;
+            }
+            setPropertyDocument(KEY_PERSON, documents);
             return this;
         }
 
@@ -422,8 +532,7 @@
          */
         @NonNull
         public Builder setRank(final int rank) {
-            Preconditions.checkArgument((0 <= rank),
-                    "Rank cannot be negative or bigger than MAX_RANK");
+            Preconditions.checkArgument((0 <= rank), "Rank cannot be negative");
             setPropertyLong(KEY_RANK, rank);
             return this;
         }
@@ -432,6 +541,15 @@
          * @hide
          */
         @NonNull
+        public Builder setImplicitRank(final int rank) {
+            setPropertyLong(KEY_IMPLICIT_RANK, rank);
+            return this;
+        }
+
+        /**
+         * @hide
+         */
+        @NonNull
         public Builder setExtras(@Nullable final PersistableBundle extras) {
             if (extras != null) {
                 setPropertyBytes(KEY_EXTRAS, transformToByteArray(extras));
@@ -444,7 +562,7 @@
          */
         public Builder setPackageName(@Nullable final String packageName) {
             if (!TextUtils.isEmpty(packageName)) {
-                setPropertyString(KEY_PACKAGE_NAME, packageName);
+                setNamespace(packageName);
             }
             return this;
         }
@@ -579,7 +697,14 @@
 
     @NonNull
     private static Person[] parsePerson(@Nullable final GenericDocument[] persons) {
-        return persons == null ? new Person[0] : Arrays.stream(persons).map(it ->
-                ((AppSearchPerson) it).toPerson()).toArray(Person[]::new);
+        if (persons == null) return new Person[0];
+        final Person[] ret = new Person[persons.length];
+        for (int i = 0; i < persons.length; i++) {
+            final GenericDocument document = persons[i];
+            if (document == null) continue;
+            final AppSearchPerson person = new AppSearchPerson(document);
+            ret[i] = person.toPerson();
+        }
+        return ret;
     }
 }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index dec2c3d..0aa1be9 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -136,6 +136,18 @@
     public int fullBackupContent = 0;
 
     /**
+     * Applications can set this attribute to an xml resource within their app where they specified
+     * the rules determining which files and directories can be copied from the device as part of
+     * backup or transfer operations.
+     *<p>
+     * Set from the {@link android.R.styleable#AndroidManifestApplication_dataExtractionRules}
+     * attribute in the manifest.
+     *
+     * @hide
+     */
+    public int dataExtractionRulesRes = 0;
+
+    /**
      * <code>true</code> if the package is capable of presenting a unified interface representing
      * multiple profiles.
      * @hide
@@ -1520,6 +1532,9 @@
                 pw.println(prefix + "fullBackupContent="
                         + (fullBackupContent < 0 ? "false" : "true"));
             }
+            if (dataExtractionRulesRes != 0) {
+                pw.println(prefix + "dataExtractionRules=@xml/" + dataExtractionRulesRes);
+            }
             pw.println(prefix + "crossProfile=" + (crossProfile ? "true" : "false"));
             if (networkSecurityConfigRes != 0) {
                 pw.println(prefix + "networkSecurityConfigRes=0x"
@@ -1749,6 +1764,7 @@
         uiOptions = orig.uiOptions;
         backupAgentName = orig.backupAgentName;
         fullBackupContent = orig.fullBackupContent;
+        dataExtractionRulesRes = orig.dataExtractionRulesRes;
         crossProfile = orig.crossProfile;
         networkSecurityConfigRes = orig.networkSecurityConfigRes;
         category = orig.category;
@@ -1836,6 +1852,7 @@
         dest.writeInt(descriptionRes);
         dest.writeInt(uiOptions);
         dest.writeInt(fullBackupContent);
+        dest.writeInt(dataExtractionRulesRes);
         dest.writeBoolean(crossProfile);
         dest.writeInt(networkSecurityConfigRes);
         dest.writeInt(category);
@@ -1920,6 +1937,7 @@
         descriptionRes = source.readInt();
         uiOptions = source.readInt();
         fullBackupContent = source.readInt();
+        dataExtractionRulesRes = source.readInt();
         crossProfile = source.readBoolean();
         networkSecurityConfigRes = source.readInt();
         category = source.readInt();
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index b290679..48b634e 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -19,6 +19,7 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.app.Activity;
 import android.app.AppOpsManager.Mode;
 import android.content.ComponentName;
@@ -418,6 +419,7 @@
      *
      * @hide
      */
+    @TestApi
     public boolean canConfigureInteractAcrossProfiles(@NonNull String packageName) {
         try {
             return mService.canConfigureInteractAcrossProfiles(packageName);
diff --git a/core/java/android/content/pm/DataLoaderParamsParcel.aidl b/core/java/android/content/pm/DataLoaderParamsParcel.aidl
index d40012fd..29d472e 100644
--- a/core/java/android/content/pm/DataLoaderParamsParcel.aidl
+++ b/core/java/android/content/pm/DataLoaderParamsParcel.aidl
@@ -23,7 +23,7 @@
  * @hide
  */
 parcelable DataLoaderParamsParcel {
-    DataLoaderType type;
+    DataLoaderType type = DataLoaderType.NONE;
     @utf8InCpp String packageName;
     @utf8InCpp String className;
     @utf8InCpp String arguments;
diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl
index 29a55b7..b345748 100644
--- a/core/java/android/content/pm/IShortcutService.aidl
+++ b/core/java/android/content/pm/IShortcutService.aidl
@@ -78,4 +78,7 @@
     ParceledListSlice getShortcuts(String packageName, int matchFlags, int userId);
 
     void pushDynamicShortcut(String packageName, in ShortcutInfo shortcut, int userId);
+
+    void updateShortcutVisibility(String callingPkg, String packageName, in byte[] certificate,
+            in boolean visible, int userId);
 }
\ No newline at end of file
diff --git a/core/java/android/content/pm/InstallationFileParcel.aidl b/core/java/android/content/pm/InstallationFileParcel.aidl
index b7efc19..09d1a32 100644
--- a/core/java/android/content/pm/InstallationFileParcel.aidl
+++ b/core/java/android/content/pm/InstallationFileParcel.aidl
@@ -24,7 +24,7 @@
  */
 parcelable InstallationFileParcel {
     String name;
-    InstallationFileLocation location;
+    InstallationFileLocation location = InstallationFileLocation.UNKNOWN;
     long size;
     byte[] metadata;
     byte[] signature;
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 567501c..42cbe35 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1173,7 +1173,6 @@
          * {@hide}
          */
         @SystemApi
-        @RequiresPermission(android.Manifest.permission.USE_INSTALLER_V2)
         public @Nullable DataLoaderParams getDataLoaderParams() {
             try {
                 DataLoaderParamsParcel data = mSession.getDataLoaderParams();
@@ -1213,7 +1212,6 @@
          * {@hide}
          */
         @SystemApi
-        @RequiresPermission(android.Manifest.permission.USE_INSTALLER_V2)
         public void addFile(@FileLocation int location, @NonNull String name, long lengthBytes,
                 @NonNull byte[] metadata, @Nullable byte[] signature) {
             try {
@@ -1237,7 +1235,6 @@
          * {@hide}
          */
         @SystemApi
-        @RequiresPermission(android.Manifest.permission.USE_INSTALLER_V2)
         public void removeFile(@FileLocation int location, @NonNull String name) {
             try {
                 mSession.removeFile(location, name);
@@ -2050,9 +2047,7 @@
          * {@hide}
          */
         @SystemApi
-        @RequiresPermission(allOf = {
-                Manifest.permission.INSTALL_PACKAGES,
-                Manifest.permission.USE_INSTALLER_V2})
+        @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
         public void setDataLoaderParams(@NonNull DataLoaderParams dataLoaderParams) {
             this.dataLoaderParams = dataLoaderParams;
         }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index f9122b1..7b62f3b 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3584,30 +3584,18 @@
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has
      * the requisite kernel support to support incremental delivery aka Incremental FileSystem.
      *
-     * @see IncrementalManager#isFeatureEnabled
-     * @hide
-     *
-     * @deprecated Use {@link #FEATURE_INCREMENTAL_DELIVERY_VERSION} instead.
-     */
-    @Deprecated
-    @SystemApi
-    @SdkConstant(SdkConstantType.FEATURE)
-    public static final String FEATURE_INCREMENTAL_DELIVERY =
-            "android.software.incremental_delivery";
-
-    /**
-     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
      * feature not present - IncFs is not present on the device.
      * 1 - IncFs v1, core features, no PerUid support. Optional in R.
      * 2 - IncFs v2, PerUid support, fs-verity support. Required in S.
      *
-     * @see IncrementalManager#isFeatureEnabled and IncrementalManager#isV2()
+     * @see IncrementalManager#isFeatureEnabled
+     * @see IncrementalManager#getVersion()
      * @hide
      */
     @SystemApi
     @SdkConstant(SdkConstantType.FEATURE)
-    public static final String FEATURE_INCREMENTAL_DELIVERY_VERSION =
-            "android.software.incremental_delivery_version";
+    public static final String FEATURE_INCREMENTAL_DELIVERY =
+            "android.software.incremental_delivery";
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
@@ -3623,11 +3611,26 @@
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device supports a enabling/disabling sensor privacy for
-     * camera. When sensory privacy for the camera is enabled no camera data is send to clients,
+     * microphone. When sensory privacy for the microphone is enabled no microphone data is sent to
+     * clients, e.g. all audio data is silent.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_MICROPHONE_TOGGLE = "android.hardware.microphone.toggle";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device supports a enabling/disabling sensor privacy for
+     * camera. When sensory privacy for the camera is enabled no camera data is sent to clients,
      * e.g. the view finder in a camera app would appear blank.
      *
      * @hide
      */
+    @SystemApi
+    @TestApi
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_CAMERA_TOGGLE = "android.hardware.camera.toggle";
 
@@ -3641,17 +3644,6 @@
     public static final String FEATURE_APP_ENUMERATION = "android.software.app_enumeration";
 
     /**
-     * Feature for {@link android.view.WindowManager.LayoutParams.backgroundBlurRedius} and
-     * {@link android.graphics.drawable.BackgroundBlurDrawable}: the device supports cross-layer
-     * blurring.
-     *
-     * @hide
-     */
-    @SystemApi
-    @SdkConstant(SdkConstantType.FEATURE)
-    public static final String FEATURE_CROSS_LAYER_BLUR = "android.software.cross_layer_blur";
-
-    /**
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has
      * a Keystore implementation that can only enforce limited use key in hardware with max usage
      * count equals to 1.
@@ -4060,16 +4052,6 @@
     public static final int FLAG_PERMISSION_AUTO_REVOKED = 1 << 17;
 
     /**
-     * Permission flag: The permission is restricted but the app is exempt
-     * from the restriction and is allowed to hold this permission in its
-     * full form and the exemption is provided by the held roles.
-     *
-     * @hide
-     */
-    @SystemApi
-    public static final int FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT =  1 << 18;
-
-    /**
      * Permission flag: This location permission is selected as the level of granularity of
      * location accuracy.
      * Example: If this flag is set for ACCESS_FINE_LOCATION, FINE location is the selected location
@@ -4098,8 +4080,7 @@
     public static final int FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT =
             FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT
                     | FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT
-                    | FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT
-                    | FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
+                    | FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
 
     /**
      * Mask for all permission flags.
@@ -4184,20 +4165,11 @@
      */
     public static final int FLAG_PERMISSION_WHITELIST_UPGRADE = 1 << 2;
 
-    /**
-     * Permission allowlist flag: permissions exempted by the system
-     * when being granted a role.
-     * Permissions can also be exempted by the installer, the system, or on
-     * upgrade.
-     */
-    public static final int FLAG_PERMISSION_ALLOWLIST_ROLE = 1 << 3;
-
     /** @hide */
     @IntDef(flag = true, prefix = {"FLAG_PERMISSION_WHITELIST_"}, value = {
             FLAG_PERMISSION_WHITELIST_SYSTEM,
             FLAG_PERMISSION_WHITELIST_INSTALLER,
-            FLAG_PERMISSION_WHITELIST_UPGRADE,
-            FLAG_PERMISSION_ALLOWLIST_ROLE
+            FLAG_PERMISSION_WHITELIST_UPGRADE
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface PermissionWhitelistFlags {}
@@ -5229,10 +5201,6 @@
      * This list corresponds to the {@link #FLAG_PERMISSION_WHITELIST_INSTALLER} flag.
      * Can be accessed by pre-installed holders of a dedicated permission or the
      * installer on record.
-     *
-     * <li>one for cases where the system exempts the permission when granting a role.
-     * This list corresponds to the {@link #FLAG_PERMISSION_ALLOWLIST_ROLE} flag. Can
-     * be accessed by pre-installed holders of a dedicated permission.
      * </ol>
      *
      * <p>
@@ -5251,7 +5219,6 @@
      * @see #FLAG_PERMISSION_WHITELIST_SYSTEM
      * @see #FLAG_PERMISSION_WHITELIST_UPGRADE
      * @see #FLAG_PERMISSION_WHITELIST_INSTALLER
-     * @see #FLAG_PERMISSION_ALLOWLIST_ROLE
      *
      * @throws SecurityException if you try to access a whitelist that you have no access to.
      */
@@ -5291,10 +5258,6 @@
      * This list corresponds to the {@link #FLAG_PERMISSION_WHITELIST_INSTALLER} flag.
      * Can be modified by pre-installed holders of a dedicated permission or the installer
      * on record.
-     *
-     * <li>one for cases where the system exempts the permission when permission when
-     * granting a role. This list corresponds to the {@link #FLAG_PERMISSION_ALLOWLIST_ROLE}
-     * flag. Can be modified by pre-installed holders of a dedicated permission.
      * </ol>
      *
      * <p>You need to specify the whitelists for which to set the whitelisted permissions
@@ -5318,7 +5281,6 @@
      * @see #FLAG_PERMISSION_WHITELIST_SYSTEM
      * @see #FLAG_PERMISSION_WHITELIST_UPGRADE
      * @see #FLAG_PERMISSION_WHITELIST_INSTALLER
-     * @see #FLAG_PERMISSION_ALLOWLIST_ROLE
      *
      * @throws SecurityException if you try to modify a whitelist that you have no access to.
      */
@@ -5388,7 +5350,6 @@
      * @see #FLAG_PERMISSION_WHITELIST_SYSTEM
      * @see #FLAG_PERMISSION_WHITELIST_UPGRADE
      * @see #FLAG_PERMISSION_WHITELIST_INSTALLER
-     * @see #FLAG_PERMISSION_ALLOWLIST_ROLE
      *
      * @throws SecurityException if you try to modify a whitelist that you have no access to.
      */
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 0e70a3e..83baca6 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -411,14 +411,6 @@
     public static final int FLAG_IMMUTABLY_RESTRICTED = 1<<4;
 
     /**
-     * Flag for {@link #flags}, corresponding to <code>installerExemptIgnored</code>
-     * value of {@link android.R.attr#permissionFlags}.
-     *
-     * <p> Modifier for permission restriction. This permission cannot be exempted by the installer.
-     */
-    public static final int FLAG_INSTALLER_EXEMPT_IGNORED = 1 << 5;
-
-    /**
      * Flag for {@link #flags}, indicating that this permission has been
      * installed into the system's globally defined permissions.
      */
@@ -724,11 +716,6 @@
     }
 
     /** @hide */
-    public boolean isInstallerExemptIgnored() {
-        return (flags & PermissionInfo.FLAG_INSTALLER_EXEMPT_IGNORED) != 0;
-    }
-
-    /** @hide */
     public boolean isAppOp() {
         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0;
     }
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 7ecb112..7696cbe 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -42,6 +42,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.ArrayUtils;
 
 import libcore.io.IoUtils;
@@ -161,18 +162,20 @@
         intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         intentFilter.addDataScheme("package");
-        mContext.registerReceiverAsUser(mPackageReceiver, UserHandle.ALL, intentFilter, null, null);
+        Handler handler = BackgroundThread.getHandler();
+        mContext.registerReceiverAsUser(
+                mPackageReceiver, UserHandle.ALL, intentFilter, null, handler);
 
         // Register for events related to sdcard installation.
         IntentFilter sdFilter = new IntentFilter();
         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
-        mContext.registerReceiver(mExternalReceiver, sdFilter);
+        mContext.registerReceiver(mExternalReceiver, sdFilter, null, handler);
 
         // Register for user-related events
         IntentFilter userFilter = new IntentFilter();
         sdFilter.addAction(Intent.ACTION_USER_REMOVED);
-        mContext.registerReceiver(mUserRemovedReceiver, userFilter);
+        mContext.registerReceiver(mUserRemovedReceiver, userFilter, null, handler);
     }
 
     private void handlePackageEvent(Intent intent, int userId) {
@@ -265,7 +268,7 @@
 
     public void setListener(RegisteredServicesCacheListener<V> listener, Handler handler) {
         if (handler == null) {
-            handler = new Handler(mContext.getMainLooper());
+            handler = BackgroundThread.getHandler();
         }
         synchronized (this) {
             mHandler = handler;
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 5f80ba1..275e81c 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -68,7 +68,8 @@
 
     private static final int IMPLICIT_RANK_MASK = 0x7fffffff;
 
-    private static final int RANK_CHANGED_BIT = ~IMPLICIT_RANK_MASK;
+    /** @hide */
+    public static final int RANK_CHANGED_BIT = ~IMPLICIT_RANK_MASK;
 
     /** @hide */
     public static final int RANK_NOT_SET = Integer.MAX_VALUE;
@@ -1595,6 +1596,9 @@
      */
     @Nullable
     public Intent[] getIntents() {
+        if (mIntents == null) {
+            return null;
+        }
         final Intent[] ret = new Intent[mIntents.length];
 
         for (int i = 0; i < ret.length; i++) {
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 35c99a1..d3bac79 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -39,6 +39,7 @@
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -771,4 +772,20 @@
         }
     }
 
+    /**
+     * 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 {
+            mService.updateShortcutVisibility(mContext.getPackageName(), packageName, certificate,
+                    visible, injectMyUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index d81dff8..cfb6e1b 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.TestApi;
 import android.annotation.UserIdInt;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
@@ -47,6 +48,7 @@
  *
  * @hide
  */
+@TestApi
 public class UserInfo implements Parcelable {
 
     /**
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index 7a01392..29edd40 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -260,6 +260,8 @@
 
     ParsingPackage setFullBackupContent(int fullBackupContent);
 
+    ParsingPackage setDataExtractionRules(int dataExtractionRules);
+
     ParsingPackage setHasDomainUrls(boolean hasDomainUrls);
 
     ParsingPackage setIconRes(int iconRes);
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index c1a93d8..067787d 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -334,6 +334,7 @@
     private int descriptionRes;
 
     private int fullBackupContent;
+    private int dataExtractionRules;
     private int iconRes;
     private int installLocation = ParsingPackageUtils.PARSE_DEFAULT_INSTALL_LOCATION;
     private int labelRes;
@@ -1015,6 +1016,7 @@
         appInfo.enabled = getBoolean(Booleans.ENABLED);
 //        appInfo.enabledSetting
         appInfo.fullBackupContent = fullBackupContent;
+        appInfo.dataExtractionRulesRes = dataExtractionRules;
         // TODO(b/135203078): See ParsingPackageImpl#getHiddenApiEnforcementPolicy
 //        appInfo.mHiddenApiPolicy
 //        appInfo.hiddenUntilInstalled
@@ -1163,6 +1165,7 @@
         dest.writeInt(this.compatibleWidthLimitDp);
         dest.writeInt(this.descriptionRes);
         dest.writeInt(this.fullBackupContent);
+        dest.writeInt(this.dataExtractionRules);
         dest.writeInt(this.iconRes);
         dest.writeInt(this.installLocation);
         dest.writeInt(this.labelRes);
@@ -1284,6 +1287,7 @@
         this.compatibleWidthLimitDp = in.readInt();
         this.descriptionRes = in.readInt();
         this.fullBackupContent = in.readInt();
+        this.dataExtractionRules = in.readInt();
         this.iconRes = in.readInt();
         this.installLocation = in.readInt();
         this.labelRes = in.readInt();
@@ -1808,6 +1812,11 @@
     }
 
     @Override
+    public int getDataExtractionRules() {
+        return dataExtractionRules;
+    }
+
+    @Override
     public int getIconRes() {
         return iconRes;
     }
@@ -2264,6 +2273,12 @@
     }
 
     @Override
+    public ParsingPackageImpl setDataExtractionRules(int value) {
+        dataExtractionRules = value;
+        return this;
+    }
+
+    @Override
     public ParsingPackageImpl setIconRes(int value) {
         iconRes = value;
         return this;
diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java
index ff4cebd..f7f3e19 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageRead.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java
@@ -587,6 +587,11 @@
      */
     int getFullBackupContent();
 
+    /**
+     * @see R.styleable#AndroidManifestApplication_dataExtractionRules
+     */
+    int getDataExtractionRules();
+
     /** @see ApplicationInfo#PRIVATE_FLAG_HAS_DOMAIN_URLS */
     boolean isHasDomainUrls();
 
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index b7aa30f..0c033fd 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -2168,6 +2168,8 @@
                 .setNetworkSecurityConfigRes(resId(R.styleable.AndroidManifestApplication_networkSecurityConfig, sa))
                 .setRoundIconRes(resId(R.styleable.AndroidManifestApplication_roundIcon, sa))
                 .setTheme(resId(R.styleable.AndroidManifestApplication_theme, sa))
+                .setDataExtractionRules(
+                        resId(R.styleable.AndroidManifestApplication_dataExtractionRules, sa))
                 // Strings
                 .setClassLoaderName(string(R.styleable.AndroidManifestApplication_classLoader, sa))
                 .setRequiredAccountType(string(R.styleable.AndroidManifestApplication_requiredAccountType, sa))
diff --git a/core/java/android/content/pm/permission/OWNERS b/core/java/android/content/pm/permission/OWNERS
index d302b0a..cf7e689 100644
--- a/core/java/android/content/pm/permission/OWNERS
+++ b/core/java/android/content/pm/permission/OWNERS
@@ -1,10 +1,8 @@
 # Bug component: 137825
 
+include platform/frameworks/base:/core/java/android/permission/OWNERS
+
 toddke@android.com
 toddke@google.com
 patb@google.com
-svetoslavganov@android.com
-svetoslavganov@google.com
-zhanghai@google.com
-evanseverson@google.com
-ntmyren@google.com
+
diff --git a/core/java/android/content/pm/verify/domain/DomainOwner.aidl b/core/java/android/content/pm/verify/domain/DomainOwner.aidl
new file mode 100644
index 0000000..41366d1
--- /dev/null
+++ b/core/java/android/content/pm/verify/domain/DomainOwner.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.content.pm.verify.domain;
+
+parcelable DomainOwner;
diff --git a/core/java/android/content/pm/verify/domain/DomainOwner.java b/core/java/android/content/pm/verify/domain/DomainOwner.java
new file mode 100644
index 0000000..b050f5d
--- /dev/null
+++ b/core/java/android/content/pm/verify/domain/DomainOwner.java
@@ -0,0 +1,219 @@
+/*
+ * 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.content.pm.verify.domain;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * @hide
+ */
+@SystemApi
+@DataClass(genParcelable = true, genEqualsHashCode = true, genAidl = true, genToString = true)
+public final class DomainOwner implements Parcelable {
+
+    /**
+     * Package name of that owns the domain.
+     */
+    @NonNull
+    private final String mPackageName;
+
+    /**
+     * Whether or not this owner can be automatically overridden.
+     *
+     * @see DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set, boolean)
+     */
+    private final boolean mOverrideable;
+
+
+
+    // Code below generated by codegen v1.0.22.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain/DomainOwner.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * Creates a new DomainOwner.
+     *
+     * @param packageName
+     *   Package name of that owns the domain.
+     * @param overrideable
+     *   Whether or not this owner can be automatically overridden. If all owners for a domain are
+     *   overrideable, then calling
+     *   {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
+     *   Set, boolean)} to enable the domain will disable all other owners. On the other hand, if any
+     *   of the owners are non-overrideable, then
+     *   {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String,
+     *   boolean)} must be called with false to disable all of the other owners before this domain can
+     *   be taken by a new owner through
+     *   {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
+     *   Set, boolean)}.
+     */
+    @DataClass.Generated.Member
+    public DomainOwner(
+            @NonNull String packageName,
+            boolean overrideable) {
+        this.mPackageName = packageName;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mPackageName);
+        this.mOverrideable = overrideable;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * Package name of that owns the domain.
+     */
+    @DataClass.Generated.Member
+    public @NonNull String getPackageName() {
+        return mPackageName;
+    }
+
+    /**
+     * Whether or not this owner can be automatically overridden. If all owners for a domain are
+     * overrideable, then calling
+     * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
+     * Set, boolean)} to enable the domain will disable all other owners. On the other hand, if any
+     * of the owners are non-overrideable, then
+     * {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String,
+     * boolean)} must be called with false to disable all of the other owners before this domain can
+     * be taken by a new owner through
+     * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
+     * Set, boolean)}.
+     */
+    @DataClass.Generated.Member
+    public boolean isOverrideable() {
+        return mOverrideable;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "DomainOwner { " +
+                "packageName = " + mPackageName + ", " +
+                "overrideable = " + mOverrideable +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public boolean equals(@android.annotation.Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(DomainOwner other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        DomainOwner that = (DomainOwner) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && java.util.Objects.equals(mPackageName, that.mPackageName)
+                && mOverrideable == that.mOverrideable;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int hashCode() {
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + java.util.Objects.hashCode(mPackageName);
+        _hash = 31 * _hash + Boolean.hashCode(mOverrideable);
+        return _hash;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        byte flg = 0;
+        if (mOverrideable) flg |= 0x2;
+        dest.writeByte(flg);
+        dest.writeString(mPackageName);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ DomainOwner(@NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte flg = in.readByte();
+        boolean overrideable = (flg & 0x2) != 0;
+        String packageName = in.readString();
+
+        this.mPackageName = packageName;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mPackageName);
+        this.mOverrideable = overrideable;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<DomainOwner> CREATOR
+            = new Parcelable.Creator<DomainOwner>() {
+        @Override
+        public DomainOwner[] newArray(int size) {
+            return new DomainOwner[size];
+        }
+
+        @Override
+        public DomainOwner createFromParcel(@NonNull android.os.Parcel in) {
+            return new DomainOwner(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1614119379978L,
+            codegenVersion = "1.0.22",
+            sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainOwner.java",
+            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final  boolean mOverrideable\nclass DomainOwner extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genEqualsHashCode=true, genAidl=true, genToString=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/content/pm/verify/domain/DomainSet.aidl b/core/java/android/content/pm/verify/domain/DomainSet.aidl
new file mode 100644
index 0000000..fab131d
--- /dev/null
+++ b/core/java/android/content/pm/verify/domain/DomainSet.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.content.pm.verify.domain;
+
+parcelable DomainSet;
diff --git a/core/java/android/content/pm/verify/domain/DomainSet.java b/core/java/android/content/pm/verify/domain/DomainSet.java
new file mode 100644
index 0000000..243ff08
--- /dev/null
+++ b/core/java/android/content/pm/verify/domain/DomainSet.java
@@ -0,0 +1,160 @@
+/*
+ * 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.content.pm.verify.domain;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+import java.util.Set;
+
+/**
+ * Wraps an input set of domains from the client process, to be sent to the server. Handles cases
+ * where the data size is too large by writing data using {@link Parcel#writeBlob(byte[])}.
+ *
+ * @hide
+ */
+@DataClass(genParcelable = true, genAidl = true, genEqualsHashCode = true)
+public class DomainSet implements Parcelable {
+
+    @NonNull
+    private final Set<String> mDomains;
+
+    private void parcelDomains(@NonNull Parcel dest, @SuppressWarnings("unused") int flags) {
+        DomainVerificationUtils.writeHostSet(dest, mDomains);
+    }
+
+    private Set<String> unparcelDomains(@NonNull Parcel in) {
+        return DomainVerificationUtils.readHostSet(in);
+    }
+
+
+
+    // Code below generated by codegen v1.0.22.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain
+    // /DomainSet.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    @DataClass.Generated.Member
+    public DomainSet(
+            @NonNull Set<String> domains) {
+        this.mDomains = domains;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mDomains);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull Set<String> getDomains() {
+        return mDomains;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public boolean equals(@android.annotation.Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(DomainSet other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        DomainSet that = (DomainSet) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && java.util.Objects.equals(mDomains, that.mDomains);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int hashCode() {
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + java.util.Objects.hashCode(mDomains);
+        return _hash;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        parcelDomains(dest, flags);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    protected DomainSet(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        Set<String> domains = unparcelDomains(in);
+
+        this.mDomains = domains;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mDomains);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<DomainSet> CREATOR
+            = new Parcelable.Creator<DomainSet>() {
+        @Override
+        public DomainSet[] newArray(int size) {
+            return new DomainSet[size];
+        }
+
+        @Override
+        public DomainSet createFromParcel(@NonNull Parcel in) {
+            return new DomainSet(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1613169242020L,
+            codegenVersion = "1.0.22",
+            sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainSet.java",
+            inputSignatures = "private final @android.annotation.NonNull java.util.Set<java.lang.String> mDomains\nprivate  void parcelDomains(android.os.Parcel,int)\nprivate  java.util.Set<java.lang.String> unparcelDomains(android.os.Parcel)\nclass DomainSet extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genEqualsHashCode=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java b/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java
index 7afbe1f..8095875 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java
+++ b/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java
@@ -19,7 +19,9 @@
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.content.pm.PackageManager;
+import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.ArrayMap;
 
 import com.android.internal.util.DataClass;
 import com.android.internal.util.Parcelling;
@@ -34,12 +36,12 @@
  * against the digital asset links response from the server hosting that domain.
  * <p>
  * These values for each domain can be modified through
- * {@link DomainVerificationManager#setDomainVerificationStatus(UUID, Set, int)}.
+ * {@link DomainVerificationManager#setDomainVerificationStatus(UUID,
+ * Set, int)}.
  *
  * @hide
  */
 @SystemApi
-@SuppressWarnings("DefaultAnnotationParam")
 @DataClass(genAidl = true, genHiddenConstructor = true, genParcelable = true, genToString = true,
         genEqualsHashCode = true)
 public final class DomainVerificationInfo implements Parcelable {
@@ -71,22 +73,30 @@
     private final String mPackageName;
 
     /**
-     * Map of host names to their current state. State is an integer, which defaults to
-     * {@link DomainVerificationManager#STATE_NO_RESPONSE}. State can be modified by the
-     * domain verification agent (the intended consumer of this API), which can be equal
-     * to {@link DomainVerificationManager#STATE_SUCCESS} when verified, or equal to or
-     * greater than {@link DomainVerificationManager#STATE_FIRST_VERIFIER_DEFINED} for
-     * any unsuccessful response.
+     * Map of host names to their current state. State is an integer, which defaults to {@link
+     * DomainVerificationManager#STATE_NO_RESPONSE}. State can be modified by the domain
+     * verification agent (the intended consumer of this API), which can be equal to {@link
+     * DomainVerificationManager#STATE_SUCCESS} when verified, or equal to or greater than {@link
+     * DomainVerificationManager#STATE_FIRST_VERIFIER_DEFINED} for any unsuccessful response.
      * <p>
-     * Any value non-inclusive between those 2 values are reserved for use by the system.
-     * The domain verification agent may be able to act on these reserved values, and this
-     * ability can be queried using {@link DomainVerificationManager#isStateModifiable(int)}.
-     * It is expected that the agent attempt to verify all domains that it can modify the
-     * state of, even if it does not understand the meaning of those values.
+     * Any value non-inclusive between those 2 values are reserved for use by the system. The domain
+     * verification agent may be able to act on these reserved values, and this ability can be
+     * queried using {@link DomainVerificationManager#isStateModifiable(int)}. It is expected that
+     * the agent attempt to verify all domains that it can modify the state of, even if it does not
+     * understand the meaning of those values.
      */
     @NonNull
     private final Map<String, Integer> mHostToStateMap;
 
+    private void parcelHostToStateMap(Parcel dest, @SuppressWarnings("unused") int flags) {
+        DomainVerificationUtils.writeHostMap(dest, mHostToStateMap);
+    }
+
+    private Map<String, Integer> unparcelHostToStateMap(Parcel in) {
+        return DomainVerificationUtils.readHostMap(in, new ArrayMap<>(),
+                DomainVerificationUserSelection.class.getClassLoader());
+    }
+
 
 
     // Code below generated by codegen v1.0.22.
@@ -95,7 +105,8 @@
     // CHECKSTYLE:OFF Generated code
     //
     // To regenerate run:
-    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain
+    // /DomainVerificationInfo.java
     //
     // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
     //   Settings > Editor > Code Style > Formatter Control
@@ -123,18 +134,17 @@
      * @param packageName
      *   The package name that this data corresponds to.
      * @param hostToStateMap
-     *   Map of host names to their current state. State is an integer, which defaults to
-     *   {@link DomainVerificationManager#STATE_NO_RESPONSE}. State can be modified by the
-     *   domain verification agent (the intended consumer of this API), which can be equal
-     *   to {@link DomainVerificationManager#STATE_SUCCESS} when verified, or equal to or
-     *   greater than {@link DomainVerificationManager#STATE_FIRST_VERIFIER_DEFINED} for
-     *   any unsuccessful response.
+     *   Map of host names to their current state. State is an integer, which defaults to {@link
+     *   DomainVerificationManager#STATE_NO_RESPONSE}. State can be modified by the domain
+     *   verification agent (the intended consumer of this API), which can be equal to {@link
+     *   DomainVerificationManager#STATE_SUCCESS} when verified, or equal to or greater than {@link
+     *   DomainVerificationManager#STATE_FIRST_VERIFIER_DEFINED} for any unsuccessful response.
      *   <p>
-     *   Any value non-inclusive between those 2 values are reserved for use by the system.
-     *   The domain verification agent may be able to act on these reserved values, and this
-     *   ability can be queried using {@link DomainVerificationManager#isStateModifiable(int)}.
-     *   It is expected that the agent attempt to verify all domains that it can modify the
-     *   state of, even if it does not understand the meaning of those values.
+     *   Any value non-inclusive between those 2 values are reserved for use by the system. The domain
+     *   verification agent may be able to act on these reserved values, and this ability can be
+     *   queried using {@link DomainVerificationManager#isStateModifiable(int)}. It is expected that
+     *   the agent attempt to verify all domains that it can modify the state of, even if it does not
+     *   understand the meaning of those values.
      * @hide
      */
     @DataClass.Generated.Member
@@ -185,18 +195,17 @@
     }
 
     /**
-     * Map of host names to their current state. State is an integer, which defaults to
-     * {@link DomainVerificationManager#STATE_NO_RESPONSE}. State can be modified by the
-     * domain verification agent (the intended consumer of this API), which can be equal
-     * to {@link DomainVerificationManager#STATE_SUCCESS} when verified, or equal to or
-     * greater than {@link DomainVerificationManager#STATE_FIRST_VERIFIER_DEFINED} for
-     * any unsuccessful response.
+     * Map of host names to their current state. State is an integer, which defaults to {@link
+     * DomainVerificationManager#STATE_NO_RESPONSE}. State can be modified by the domain
+     * verification agent (the intended consumer of this API), which can be equal to {@link
+     * DomainVerificationManager#STATE_SUCCESS} when verified, or equal to or greater than {@link
+     * DomainVerificationManager#STATE_FIRST_VERIFIER_DEFINED} for any unsuccessful response.
      * <p>
-     * Any value non-inclusive between those 2 values are reserved for use by the system.
-     * The domain verification agent may be able to act on these reserved values, and this
-     * ability can be queried using {@link DomainVerificationManager#isStateModifiable(int)}.
-     * It is expected that the agent attempt to verify all domains that it can modify the
-     * state of, even if it does not understand the meaning of those values.
+     * Any value non-inclusive between those 2 values are reserved for use by the system. The domain
+     * verification agent may be able to act on these reserved values, and this ability can be
+     * queried using {@link DomainVerificationManager#isStateModifiable(int)}. It is expected that
+     * the agent attempt to verify all domains that it can modify the state of, even if it does not
+     * understand the meaning of those values.
      */
     @DataClass.Generated.Member
     public @NonNull Map<String,Integer> getHostToStateMap() {
@@ -260,13 +269,13 @@
 
     @Override
     @DataClass.Generated.Member
-    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         // You can override field parcelling by defining methods like:
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
         sParcellingForIdentifier.parcel(mIdentifier, dest, flags);
         dest.writeString(mPackageName);
-        dest.writeMap(mHostToStateMap);
+        parcelHostToStateMap(dest, flags);
     }
 
     @Override
@@ -276,14 +285,13 @@
     /** @hide */
     @SuppressWarnings({"unchecked", "RedundantCast"})
     @DataClass.Generated.Member
-    /* package-private */ DomainVerificationInfo(@NonNull android.os.Parcel in) {
+    /* package-private */ DomainVerificationInfo(@NonNull Parcel in) {
         // You can override field unparcelling by defining methods like:
         // static FieldType unparcelFieldName(Parcel in) { ... }
 
         UUID identifier = sParcellingForIdentifier.unparcel(in);
         String packageName = in.readString();
-        Map<String,Integer> hostToStateMap = new java.util.LinkedHashMap<>();
-        in.readMap(hostToStateMap, Integer.class.getClassLoader());
+        Map<String,Integer> hostToStateMap = unparcelHostToStateMap(in);
 
         this.mIdentifier = identifier;
         com.android.internal.util.AnnotationValidations.validate(
@@ -307,16 +315,16 @@
         }
 
         @Override
-        public DomainVerificationInfo createFromParcel(@NonNull android.os.Parcel in) {
+        public DomainVerificationInfo createFromParcel(@NonNull Parcel in) {
             return new DomainVerificationInfo(in);
         }
     };
 
     @DataClass.Generated(
-            time = 1611862790369L,
+            time = 1613002530369L,
             codegenVersion = "1.0.22",
             sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java",
-            inputSignatures = "private final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForUUID.class) java.util.UUID mIdentifier\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Integer> mHostToStateMap\nclass DomainVerificationInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true, genHiddenConstructor=true, genParcelable=true, genToString=true, genEqualsHashCode=true)")
+            inputSignatures = "private final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForUUID.class) java.util.UUID mIdentifier\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Integer> mHostToStateMap\nprivate  void parcelHostToStateMap(android.os.Parcel,int)\nprivate  java.util.Map<java.lang.String,java.lang.Integer> unparcelHostToStateMap(android.os.Parcel)\nclass DomainVerificationInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true, genHiddenConstructor=true, genParcelable=true, genToString=true, genEqualsHashCode=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationManager.java b/core/java/android/content/pm/verify/domain/DomainVerificationManager.java
index cbb3baa..11402af 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationManager.java
+++ b/core/java/android/content/pm/verify/domain/DomainVerificationManager.java
@@ -239,7 +239,15 @@
      * {@link Context#createPackageContextAsUser(String, int, UserHandle)} should be used.
      *
      * Enabling an unverified domain will allow an application to open it, but this can only occur
-     * if no other app on the device is approved for the domain.
+     * if no other app on the device is approved for a higher approval level. This can queried
+     * using {@link #getOwnersForDomain(String)}.
+     *
+     * If all owners for a domain are {@link DomainOwner#isOverrideable()}, then calling this to
+     * enable that domain will disable all other owners.
+     *
+     * On the other hand, if any of the owners are non-overrideable, then this must be called with
+     * false for all of the other owners to disable them before the domain can be taken by a new
+     * owner.
      *
      * @param domainSetId See {@link DomainVerificationInfo#getIdentifier()}.
      * @param domains     The domains to toggle the state of.
@@ -276,6 +284,19 @@
             throws NameNotFoundException;
 
     /**
+     * For the given domain, return all apps which are approved to open it in a
+     * greater than 0 priority. This does not mean that all apps can actually open
+     * an Intent with that domain. That will be decided by the set of apps which
+     * are the highest priority level, ignoring all lower priority levels.
+     *
+     * By default the list will be returned ordered from lowest to highest
+     * priority.
+     */
+    @NonNull
+    @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION)
+    List<DomainOwner> getOwnersForDomain(@NonNull String domain);
+
+    /**
      * Thrown if a {@link DomainVerificationInfo#getIdentifier()}} or an associated set of domains
      * provided by the caller is no longer valid. This may be recoverable, and the caller should
      * re-query the package name associated with the ID using
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationManagerImpl.java b/core/java/android/content/pm/verify/domain/DomainVerificationManagerImpl.java
index 5938def..8b9865c 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationManagerImpl.java
+++ b/core/java/android/content/pm/verify/domain/DomainVerificationManagerImpl.java
@@ -21,11 +21,9 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.verify.domain.IDomainVerificationManager;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 import java.util.UUID;
@@ -89,7 +87,7 @@
             int state) throws IllegalArgumentException, NameNotFoundException {
         try {
             mDomainVerificationManager.setDomainVerificationStatus(domainSetId.toString(),
-                    new ArrayList<>(domains), state);
+                    new DomainSet(domains), state);
         } catch (Exception e) {
             Exception converted = rethrow(e, domainSetId);
             if (converted instanceof NameNotFoundException) {
@@ -126,7 +124,7 @@
             throws IllegalArgumentException, NameNotFoundException {
         try {
             mDomainVerificationManager.setDomainVerificationUserSelection(domainSetId.toString(),
-                    new ArrayList<>(domains), enabled, mContext.getUserId());
+                    new DomainSet(domains), enabled, mContext.getUserId());
         } catch (Exception e) {
             Exception converted = rethrow(e, domainSetId);
             if (converted instanceof NameNotFoundException) {
@@ -158,6 +156,16 @@
         }
     }
 
+    @NonNull
+    @Override
+    public List<DomainOwner> getOwnersForDomain(@NonNull String domain) {
+        try {
+            return mDomainVerificationManager.getOwnersForDomain(domain, mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     private Exception rethrow(Exception exception, @Nullable UUID domainSetId) {
         return rethrow(exception, domainSetId, null);
     }
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationRequest.java b/core/java/android/content/pm/verify/domain/DomainVerificationRequest.java
index 473abce..65f6d7c 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationRequest.java
+++ b/core/java/android/content/pm/verify/domain/DomainVerificationRequest.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.content.Intent;
+import android.os.Parcel;
 import android.os.Parcelable;
 
 import com.android.internal.util.DataClass;
@@ -27,11 +28,11 @@
 import java.util.Set;
 
 /**
- * Request object sent in the {@link Intent} that's broadcast to the domain verification
- * agent, retrieved through {@link DomainVerificationManager#EXTRA_VERIFICATION_REQUEST}.
+ * Request object sent in the {@link Intent} that's broadcast to the domain verification agent,
+ * retrieved through {@link DomainVerificationManager#EXTRA_VERIFICATION_REQUEST}.
  * <p>
- * This contains the set of packages which have been invalidated and will require
- * re-verification. The exact domains can be retrieved with
+ * This contains the set of packages which have been invalidated and will require re-verification.
+ * The exact domains can be retrieved with
  * {@link DomainVerificationManager#getDomainVerificationInfo(String)}
  *
  * @hide
@@ -42,14 +43,22 @@
 public final class DomainVerificationRequest implements Parcelable {
 
     /**
-     * The package names of the apps that need to be verified. The receiver should call
-     * {@link DomainVerificationManager#getDomainVerificationInfo(String)} with each of
-     * these values to get the actual set of domains that need to be acted on.
+     * The package names of the apps that need to be verified. The receiver should call {@link
+     * DomainVerificationManager#getDomainVerificationInfo(String)} with each of these values to get
+     * the actual set of domains that need to be acted on.
      */
     @NonNull
     @DataClass.ParcelWith(Parcelling.BuiltIn.ForStringSet.class)
     private final Set<String> mPackageNames;
 
+    private void parcelPackageNames(@NonNull Parcel dest, @SuppressWarnings("unused") int flags) {
+        DomainVerificationUtils.writeHostSet(dest, mPackageNames);
+    }
+
+    private Set<String> unparcelPackageNames(@NonNull Parcel in) {
+        return DomainVerificationUtils.readHostSet(in);
+    }
+
 
 
     // Code below generated by codegen v1.0.22.
@@ -58,7 +67,8 @@
     // CHECKSTYLE:OFF Generated code
     //
     // To regenerate run:
-    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationRequest.java
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain
+    // /DomainVerificationRequest.java
     //
     // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
     //   Settings > Editor > Code Style > Formatter Control
@@ -69,9 +79,9 @@
      * Creates a new DomainVerificationRequest.
      *
      * @param packageNames
-     *   The package names of the apps that need to be verified. The receiver should call
-     *   {@link DomainVerificationManager#getDomainVerificationInfo(String)} with each of
-     *   these values to get the actual set of domains that need to be acted on.
+     *   The package names of the apps that need to be verified. The receiver should call {@link
+     *   DomainVerificationManager#getDomainVerificationInfo(String)} with each of these values to get
+     *   the actual set of domains that need to be acted on.
      * @hide
      */
     @DataClass.Generated.Member
@@ -85,9 +95,9 @@
     }
 
     /**
-     * The package names of the apps that need to be verified. The receiver should call
-     * {@link DomainVerificationManager#getDomainVerificationInfo(String)} with each of
-     * these values to get the actual set of domains that need to be acted on.
+     * The package names of the apps that need to be verified. The receiver should call {@link
+     * DomainVerificationManager#getDomainVerificationInfo(String)} with each of these values to get
+     * the actual set of domains that need to be acted on.
      */
     @DataClass.Generated.Member
     public @NonNull Set<String> getPackageNames() {
@@ -134,11 +144,11 @@
 
     @Override
     @DataClass.Generated.Member
-    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         // You can override field parcelling by defining methods like:
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
-        sParcellingForPackageNames.parcel(mPackageNames, dest, flags);
+        parcelPackageNames(dest, flags);
     }
 
     @Override
@@ -148,11 +158,11 @@
     /** @hide */
     @SuppressWarnings({"unchecked", "RedundantCast"})
     @DataClass.Generated.Member
-    /* package-private */ DomainVerificationRequest(@NonNull android.os.Parcel in) {
+    /* package-private */ DomainVerificationRequest(@NonNull Parcel in) {
         // You can override field unparcelling by defining methods like:
         // static FieldType unparcelFieldName(Parcel in) { ... }
 
-        Set<String> packageNames = sParcellingForPackageNames.unparcel(in);
+        Set<String> packageNames = unparcelPackageNames(in);
 
         this.mPackageNames = packageNames;
         com.android.internal.util.AnnotationValidations.validate(
@@ -170,16 +180,16 @@
         }
 
         @Override
-        public DomainVerificationRequest createFromParcel(@NonNull android.os.Parcel in) {
+        public DomainVerificationRequest createFromParcel(@NonNull Parcel in) {
             return new DomainVerificationRequest(in);
         }
     };
 
     @DataClass.Generated(
-            time = 1611862814990L,
+            time = 1613169505495L,
             codegenVersion = "1.0.22",
             sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationRequest.java",
-            inputSignatures = "private final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForStringSet.class) java.util.Set<java.lang.String> mPackageNames\nclass DomainVerificationRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genAidl=false, genEqualsHashCode=true)")
+            inputSignatures = "private final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForStringSet.class) java.util.Set<java.lang.String> mPackageNames\nprivate  void parcelPackageNames(android.os.Parcel,int)\nprivate  java.util.Set<java.lang.String> unparcelPackageNames(android.os.Parcel)\nclass DomainVerificationRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genAidl=false, genEqualsHashCode=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java b/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java
index 73346ef..d23f5f1 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java
+++ b/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java
@@ -20,8 +20,10 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.content.Context;
+import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.UserHandle;
+import android.util.ArrayMap;
 
 import com.android.internal.util.DataClass;
 import com.android.internal.util.Parcelling;
@@ -40,29 +42,46 @@
  * toggle affects <b>all</b> links and is not based on the verification state of the domains.
  * <p>
  * Assuming the toggle is enabled, the user can also select additional unverified domains to grant
- * to the application to open, which is reflected in {@link #getHostToUserSelectionMap()}. But only
- * a single application can be approved for a domain unless the applications are both approved. If
- * another application is approved, the user will not be allowed to enable the domain.
+ * to the application to open, which is reflected in {@link #getHostToStateMap()}. But only a single
+ * application can be approved for a domain unless the applications are both approved. If another
+ * application is approved, the user will not be allowed to enable the domain.
  * <p>
  * These values can be changed through the
  * {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String,
- * boolean)} and
- * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set,
+ * boolean)} and {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set,
  * boolean)} APIs.
  * <p>
- * Note that because state is per user, if a different user needs to be changed, one will
- * need to use {@link Context#createContextAsUser(UserHandle, int)} and hold the
- * {@link android.Manifest.permission#INTERACT_ACROSS_USERS} permission.
+ * Note that because state is per user, if a different user needs to be changed, one will need to
+ * use {@link Context#createContextAsUser(UserHandle, int)} and hold the {@link
+ * android.Manifest.permission#INTERACT_ACROSS_USERS} permission.
  *
  * @hide
  */
 @SystemApi
 @SuppressWarnings("DefaultAnnotationParam")
 @DataClass(genAidl = true, genHiddenConstructor = true, genParcelable = true, genToString = true,
-        genEqualsHashCode = true)
+        genEqualsHashCode = true, genHiddenConstDefs = true)
 public final class DomainVerificationUserSelection implements Parcelable {
 
     /**
+     * The domain is unverified and unselected, and the application is unable to open web links
+     * that resolve to the domain.
+     */
+    public static final int DOMAIN_STATE_NONE = 0;
+
+    /**
+     * The domain has been selected through the
+     * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set, boolean)}
+     * API, under the assumption it has not been reset by the system.
+     */
+    public static final int DOMAIN_STATE_SELECTED = 1;
+
+    /**
+     * The domain has been previously verified by the domain verification agent.
+     */
+    public static final int DOMAIN_STATE_VERIFIED = 2;
+
+    /**
      * @see DomainVerificationInfo#getIdentifier
      */
     @NonNull
@@ -88,15 +107,20 @@
     private final boolean mLinkHandlingAllowed;
 
     /**
-     * Retrieve the existing user selection state for the matching
-     * {@link #getPackageName()}, as was previously set by
-     * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set,
-     * boolean)}.
-     *
-     * @return Map of hosts to enabled state for the given package and user.
+     * Mapping of domain host to state, as defined by {@link DomainState}.
      */
     @NonNull
-    private final Map<String, Boolean> mHostToUserSelectionMap;
+    private final Map<String, Integer> mHostToStateMap;
+
+    private void parcelHostToStateMap(Parcel dest, @SuppressWarnings("unused") int flags) {
+        DomainVerificationUtils.writeHostMap(dest, mHostToStateMap);
+    }
+
+    @NonNull
+    private Map<String, Integer> unparcelHostToStateMap(Parcel in) {
+        return DomainVerificationUtils.readHostMap(in, new ArrayMap<>(),
+                DomainVerificationUserSelection.class.getClassLoader());
+    }
 
 
 
@@ -106,14 +130,37 @@
     // CHECKSTYLE:OFF Generated code
     //
     // To regenerate run:
-    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain
-    // /DomainVerificationUserSelection.java
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java
     //
     // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
     //   Settings > Editor > Code Style > Formatter Control
     //@formatter:off
 
 
+    /** @hide */
+    @android.annotation.IntDef(prefix = "DOMAIN_STATE_", value = {
+        DOMAIN_STATE_NONE,
+        DOMAIN_STATE_SELECTED,
+        DOMAIN_STATE_VERIFIED
+    })
+    @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+    @DataClass.Generated.Member
+    public @interface DomainState {}
+
+    /** @hide */
+    @DataClass.Generated.Member
+    public static String domainStateToString(@DomainState int value) {
+        switch (value) {
+            case DOMAIN_STATE_NONE:
+                    return "DOMAIN_STATE_NONE";
+            case DOMAIN_STATE_SELECTED:
+                    return "DOMAIN_STATE_SELECTED";
+            case DOMAIN_STATE_VERIFIED:
+                    return "DOMAIN_STATE_VERIFIED";
+            default: return Integer.toHexString(value);
+        }
+    }
+
     /**
      * Creates a new DomainVerificationUserSelection.
      *
@@ -123,11 +170,8 @@
      *   The user that this data corresponds to.
      * @param linkHandlingAllowed
      *   Whether or not this package is allowed to open links.
-     * @param hostToUserSelectionMap
-     *   Retrieve the existing user selection state for the matching
-     *   {@link #getPackageName()}, as was previously set by
-     *   {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set,
-     *   boolean)}.
+     * @param hostToStateMap
+     *   Mapping of domain host to state, as defined by {@link DomainState}.
      * @hide
      */
     @DataClass.Generated.Member
@@ -136,7 +180,7 @@
             @NonNull String packageName,
             @NonNull UserHandle user,
             @NonNull boolean linkHandlingAllowed,
-            @NonNull Map<String,Boolean> hostToUserSelectionMap) {
+            @NonNull Map<String,Integer> hostToStateMap) {
         this.mIdentifier = identifier;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mIdentifier);
@@ -149,9 +193,9 @@
         this.mLinkHandlingAllowed = linkHandlingAllowed;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mLinkHandlingAllowed);
-        this.mHostToUserSelectionMap = hostToUserSelectionMap;
+        this.mHostToStateMap = hostToStateMap;
         com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mHostToUserSelectionMap);
+                NonNull.class, null, mHostToStateMap);
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -189,16 +233,11 @@
     }
 
     /**
-     * Retrieve the existing user selection state for the matching
-     * {@link #getPackageName()}, as was previously set by
-     * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set,
-     * boolean)}.
-     *
-     * @return Map of hosts to enabled state for the given package and user.
+     * Mapping of domain host to state, as defined by {@link DomainState}.
      */
     @DataClass.Generated.Member
-    public @NonNull Map<String,Boolean> getHostToUserSelectionMap() {
-        return mHostToUserSelectionMap;
+    public @NonNull Map<String,Integer> getHostToStateMap() {
+        return mHostToStateMap;
     }
 
     @Override
@@ -212,7 +251,7 @@
                 "packageName = " + mPackageName + ", " +
                 "user = " + mUser + ", " +
                 "linkHandlingAllowed = " + mLinkHandlingAllowed + ", " +
-                "hostToUserSelectionMap = " + mHostToUserSelectionMap +
+                "hostToStateMap = " + mHostToStateMap +
         " }";
     }
 
@@ -233,7 +272,7 @@
                 && java.util.Objects.equals(mPackageName, that.mPackageName)
                 && java.util.Objects.equals(mUser, that.mUser)
                 && mLinkHandlingAllowed == that.mLinkHandlingAllowed
-                && java.util.Objects.equals(mHostToUserSelectionMap, that.mHostToUserSelectionMap);
+                && java.util.Objects.equals(mHostToStateMap, that.mHostToStateMap);
     }
 
     @Override
@@ -247,7 +286,7 @@
         _hash = 31 * _hash + java.util.Objects.hashCode(mPackageName);
         _hash = 31 * _hash + java.util.Objects.hashCode(mUser);
         _hash = 31 * _hash + Boolean.hashCode(mLinkHandlingAllowed);
-        _hash = 31 * _hash + java.util.Objects.hashCode(mHostToUserSelectionMap);
+        _hash = 31 * _hash + java.util.Objects.hashCode(mHostToStateMap);
         return _hash;
     }
 
@@ -264,7 +303,7 @@
 
     @Override
     @DataClass.Generated.Member
-    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         // You can override field parcelling by defining methods like:
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
@@ -274,7 +313,7 @@
         sParcellingForIdentifier.parcel(mIdentifier, dest, flags);
         dest.writeString(mPackageName);
         dest.writeTypedObject(mUser, flags);
-        dest.writeMap(mHostToUserSelectionMap);
+        parcelHostToStateMap(dest, flags);
     }
 
     @Override
@@ -284,7 +323,7 @@
     /** @hide */
     @SuppressWarnings({"unchecked", "RedundantCast"})
     @DataClass.Generated.Member
-    /* package-private */ DomainVerificationUserSelection(@NonNull android.os.Parcel in) {
+    /* package-private */ DomainVerificationUserSelection(@NonNull Parcel in) {
         // You can override field unparcelling by defining methods like:
         // static FieldType unparcelFieldName(Parcel in) { ... }
 
@@ -293,8 +332,7 @@
         UUID identifier = sParcellingForIdentifier.unparcel(in);
         String packageName = in.readString();
         UserHandle user = (UserHandle) in.readTypedObject(UserHandle.CREATOR);
-        Map<String,Boolean> hostToUserSelectionMap = new java.util.LinkedHashMap<>();
-        in.readMap(hostToUserSelectionMap, Boolean.class.getClassLoader());
+        Map<String,Integer> hostToStateMap = unparcelHostToStateMap(in);
 
         this.mIdentifier = identifier;
         com.android.internal.util.AnnotationValidations.validate(
@@ -308,9 +346,9 @@
         this.mLinkHandlingAllowed = linkHandlingAllowed;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mLinkHandlingAllowed);
-        this.mHostToUserSelectionMap = hostToUserSelectionMap;
+        this.mHostToStateMap = hostToStateMap;
         com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mHostToUserSelectionMap);
+                NonNull.class, null, mHostToStateMap);
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -324,16 +362,16 @@
         }
 
         @Override
-        public DomainVerificationUserSelection createFromParcel(@NonNull android.os.Parcel in) {
+        public DomainVerificationUserSelection createFromParcel(@NonNull Parcel in) {
             return new DomainVerificationUserSelection(in);
         }
     };
 
     @DataClass.Generated(
-            time = 1612829797220L,
+            time = 1613683603297L,
             codegenVersion = "1.0.22",
             sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java",
-            inputSignatures = "private final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForUUID.class) java.util.UUID mIdentifier\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull android.os.UserHandle mUser\nprivate final @android.annotation.NonNull boolean mLinkHandlingAllowed\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Boolean> mHostToUserSelectionMap\nclass DomainVerificationUserSelection extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true, genHiddenConstructor=true, genParcelable=true, genToString=true, genEqualsHashCode=true)")
+            inputSignatures = "public static final  int DOMAIN_STATE_NONE\npublic static final  int DOMAIN_STATE_SELECTED\npublic static final  int DOMAIN_STATE_VERIFIED\nprivate final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForUUID.class) java.util.UUID mIdentifier\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull android.os.UserHandle mUser\nprivate final @android.annotation.NonNull boolean mLinkHandlingAllowed\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Integer> mHostToStateMap\nprivate  void parcelHostToStateMap(android.os.Parcel,int)\nprivate @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Integer> unparcelHostToStateMap(android.os.Parcel)\nclass DomainVerificationUserSelection extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true, genHiddenConstructor=true, genParcelable=true, genToString=true, genEqualsHashCode=true, genHiddenConstDefs=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationUtils.java b/core/java/android/content/pm/verify/domain/DomainVerificationUtils.java
new file mode 100644
index 0000000..93005fa
--- /dev/null
+++ b/core/java/android/content/pm/verify/domain/DomainVerificationUtils.java
@@ -0,0 +1,181 @@
+/*
+ * 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.content.pm.verify.domain;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.util.ArraySet;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @hide
+ */
+public class DomainVerificationUtils {
+
+    private static final int STRINGS_TARGET_BYTE_SIZE = IBinder.getSuggestedMaxIpcSizeBytes() / 2;
+
+    /**
+     * Write a map containing web hosts to the given parcel, using {@link Parcel#writeBlob(byte[])}
+     * if the limit exceeds {@link IBinder#getSuggestedMaxIpcSizeBytes()} / 2. This assumes that the
+     * written map is the only data structure in the caller that varies based on the host data set.
+     * Other data that will be written to the parcel after this method will not be considered in the
+     * calculation.
+     */
+    public static void writeHostMap(@NonNull Parcel dest, @NonNull Map<String, ?> map) {
+        boolean targetSizeExceeded = false;
+        int totalSize = dest.dataSize();
+        for (String host : map.keySet()) {
+            totalSize += estimatedByteSizeOf(host);
+            if (totalSize > STRINGS_TARGET_BYTE_SIZE) {
+                targetSizeExceeded = true;
+                break;
+            }
+        }
+
+        dest.writeBoolean(targetSizeExceeded);
+
+        if (!targetSizeExceeded) {
+            dest.writeMap(map);
+            return;
+        }
+
+        Parcel data = Parcel.obtain();
+        try {
+            data.writeMap(map);
+            dest.writeBlob(data.marshall());
+        } finally {
+            data.recycle();
+        }
+    }
+
+    /**
+     * Retrieve a map previously written by {@link #writeHostMap(Parcel, Map)}.
+     */
+    @NonNull
+    @SuppressWarnings("rawtypes")
+    public static <T extends Map> T readHostMap(@NonNull Parcel in, @NonNull T map,
+            @NonNull ClassLoader classLoader) {
+        boolean targetSizeExceeded = in.readBoolean();
+
+        if (!targetSizeExceeded) {
+            in.readMap(map, classLoader);
+            return map;
+        }
+
+        Parcel data = Parcel.obtain();
+        try {
+            byte[] blob = in.readBlob();
+            data.unmarshall(blob, 0, blob.length);
+            data.setDataPosition(0);
+            data.readMap(map, classLoader);
+        } finally {
+            data.recycle();
+        }
+
+        return map;
+    }
+
+    /**
+     * {@link ArraySet} variant of {@link #writeHostMap(Parcel, Map)}.
+     */
+    public static void writeHostSet(@NonNull Parcel dest, @NonNull Set<String> set) {
+        boolean targetSizeExceeded = false;
+        int totalSize = dest.dataSize();
+        for (String host : set) {
+            totalSize += estimatedByteSizeOf(host);
+            if (totalSize > STRINGS_TARGET_BYTE_SIZE) {
+                targetSizeExceeded = true;
+                break;
+            }
+        }
+
+        dest.writeBoolean(targetSizeExceeded);
+
+        if (!targetSizeExceeded) {
+            writeSet(dest, set);
+            return;
+        }
+
+        Parcel data = Parcel.obtain();
+        try {
+            writeSet(data, set);
+            dest.writeBlob(data.marshall());
+        } finally {
+            data.recycle();
+        }
+    }
+
+    /**
+     * {@link ArraySet} variant of {@link #readHostMap(Parcel, Map, ClassLoader)}.
+     */
+    @NonNull
+    public static Set<String> readHostSet(@NonNull Parcel in) {
+        boolean targetSizeExceeded = in.readBoolean();
+
+        if (!targetSizeExceeded) {
+            return readSet(in);
+        }
+
+        Parcel data = Parcel.obtain();
+        try {
+            byte[] blob = in.readBlob();
+            data.unmarshall(blob, 0, blob.length);
+            data.setDataPosition(0);
+            return readSet(data);
+        } finally {
+            data.recycle();
+        }
+    }
+
+    private static void writeSet(@NonNull Parcel dest, @Nullable Set<String> set) {
+        if (set == null) {
+            dest.writeInt(-1);
+            return;
+        }
+        dest.writeInt(set.size());
+        for (String string : set) {
+            dest.writeString(string);
+        }
+    }
+
+    @NonNull
+    private static Set<String> readSet(@NonNull Parcel in) {
+        int size = in.readInt();
+        if (size == -1) {
+            return Collections.emptySet();
+        }
+
+        ArraySet<String> set = new ArraySet<>(size);
+        for (int count = 0; count < size; count++) {
+            set.add(in.readString());
+        }
+        return set;
+    }
+
+    /**
+     * Ballpark the size of domains to avoid unnecessary allocation of ashmem when sending domains
+     * across the client-server API.
+     */
+    public static int estimatedByteSizeOf(String string) {
+        return string.length() * 2 + 12;
+    }
+}
diff --git a/core/java/android/content/pm/verify/domain/IDomainVerificationManager.aidl b/core/java/android/content/pm/verify/domain/IDomainVerificationManager.aidl
index 21dd623b..701af32 100644
--- a/core/java/android/content/pm/verify/domain/IDomainVerificationManager.aidl
+++ b/core/java/android/content/pm/verify/domain/IDomainVerificationManager.aidl
@@ -16,6 +16,8 @@
 
 package android.content.pm.verify.domain;
 
+import android.content.pm.verify.domain.DomainOwner;
+import android.content.pm.verify.domain.DomainSet;
 import android.content.pm.verify.domain.DomainVerificationInfo;
 import android.content.pm.verify.domain.DomainVerificationUserSelection;
 import java.util.List;
@@ -35,10 +37,13 @@
     DomainVerificationUserSelection getDomainVerificationUserSelection(String packageName,
             int userId);
 
-    void setDomainVerificationStatus(String domainSetId, in List<String> domains, int state);
+    @nullable
+    List<DomainOwner> getOwnersForDomain(String domain, int userId);
+
+    void setDomainVerificationStatus(String domainSetId, in DomainSet domains, int state);
 
     void setDomainVerificationLinkHandlingAllowed(String packageName, boolean allowed, int userId);
 
-    void setDomainVerificationUserSelection(String domainSetId, in List<String> domains,
+    void setDomainVerificationUserSelection(String domainSetId, in DomainSet domains,
             boolean enabled, int userId);
 }
diff --git a/core/java/android/content/pm/verify/domain/OWNERS b/core/java/android/content/pm/verify/domain/OWNERS
new file mode 100644
index 0000000..c669112
--- /dev/null
+++ b/core/java/android/content/pm/verify/domain/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 36137
+
+chiuwinson@google.com
+patb@google.com
+toddke@google.com
\ No newline at end of file
diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java
index 2d381eb..de48ed7 100644
--- a/core/java/android/content/res/ApkAssets.java
+++ b/core/java/android/content/res/ApkAssets.java
@@ -22,6 +22,7 @@
 import android.content.om.OverlayableInfo;
 import android.content.res.loader.AssetsProvider;
 import android.content.res.loader.ResourcesProvider;
+import android.text.TextUtils;
 
 import com.android.internal.annotations.GuardedBy;
 
@@ -344,7 +345,14 @@
     @UnsupportedAppUsage
     public @NonNull String getAssetPath() {
         synchronized (this) {
-            return nativeGetAssetPath(mNativePtr);
+            return TextUtils.emptyIfNull(nativeGetAssetPath(mNativePtr));
+        }
+    }
+
+    /** @hide */
+    public @NonNull String getDebugName() {
+        synchronized (this) {
+            return nativeGetDebugName(mNativePtr);
         }
     }
 
@@ -422,7 +430,7 @@
 
     @Override
     public String toString() {
-        return "ApkAssets{path=" + getAssetPath() + "}";
+        return "ApkAssets{path=" + getDebugName() + "}";
     }
 
     /**
@@ -450,6 +458,7 @@
             @NonNull FileDescriptor fd, @NonNull String friendlyName, long offset, long length,
             @PropertyFlags int flags, @Nullable AssetsProvider asset) throws IOException;
     private static native @NonNull String nativeGetAssetPath(long ptr);
+    private static native @NonNull String nativeGetDebugName(long ptr);
     private static native long nativeGetStringBlock(long ptr);
     private static native boolean nativeIsUpToDate(long ptr);
     private static native long nativeOpenXml(long ptr, @NonNull String fileName) throws IOException;
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 2f7aeb8..b66f048 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1956,7 +1956,7 @@
         dest.writeInt(mnc);
 
         fixUpLocaleList();
-        dest.writeParcelable(mLocaleList, flags);
+        dest.writeTypedObject(mLocaleList, flags);
 
         if(userSetLocale) {
             dest.writeInt(1);
@@ -1980,7 +1980,7 @@
         dest.writeInt(compatScreenWidthDp);
         dest.writeInt(compatScreenHeightDp);
         dest.writeInt(compatSmallestScreenWidthDp);
-        dest.writeValue(windowConfiguration);
+        windowConfiguration.writeToParcel(dest, flags);
         dest.writeInt(assetsSeq);
         dest.writeInt(seq);
         dest.writeInt(fontWeightAdjustment);
@@ -1991,7 +1991,7 @@
         mcc = source.readInt();
         mnc = source.readInt();
 
-        mLocaleList = source.readParcelable(LocaleList.class.getClassLoader());
+        mLocaleList = source.readTypedObject(LocaleList.CREATOR);
         locale = mLocaleList.get(0);
 
         userSetLocale = (source.readInt()==1);
@@ -2012,7 +2012,7 @@
         compatScreenWidthDp = source.readInt();
         compatScreenHeightDp = source.readInt();
         compatSmallestScreenWidthDp = source.readInt();
-        windowConfiguration.setTo((WindowConfiguration) source.readValue(null));
+        windowConfiguration.readFromParcel(source);
         assetsSeq = source.readInt();
         seq = source.readInt();
         fontWeightAdjustment = source.readInt();
diff --git a/core/java/android/graphics/fonts/FontManager.java b/core/java/android/graphics/fonts/FontManager.java
index e512cf1..429eef9 100644
--- a/core/java/android/graphics/fonts/FontManager.java
+++ b/core/java/android/graphics/fonts/FontManager.java
@@ -20,7 +20,6 @@
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
@@ -29,7 +28,6 @@
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.text.FontConfig;
-import android.util.Log;
 
 import com.android.internal.graphics.fonts.IFontManager;
 
@@ -198,12 +196,11 @@
      * @return The current font configuration. null if failed to fetch information from the system
      *         service.
      */
-    public @Nullable FontConfig getFontConfig() {
+    public @NonNull FontConfig getFontConfig() {
         try {
             return mIFontManager.getFontConfig();
         } catch (RemoteException e) {
-            Log.e(TAG, "Failed to call getFontConfig", e);
-            return null;
+            throw e.rethrowAsRuntimeException();
         }
     }
 
diff --git a/core/java/android/hardware/SensorPrivacyManager.java b/core/java/android/hardware/SensorPrivacyManager.java
index f4f9e17..e03c1f4 100644
--- a/core/java/android/hardware/SensorPrivacyManager.java
+++ b/core/java/android/hardware/SensorPrivacyManager.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
 import android.content.Context;
@@ -33,6 +34,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
 
 /**
  * This class provides access to the sensor privacy services; sensor privacy allows the
@@ -42,9 +44,21 @@
  *
  * @hide
  */
+@SystemApi
 @TestApi
 @SystemService(Context.SENSOR_PRIVACY_SERVICE)
 public final class SensorPrivacyManager {
+
+    /**
+     * @hide
+     */
+    public static final boolean USE_MICROPHONE_TOGGLE = true;
+
+    /**
+     * @hide
+     */
+    public static final boolean USE_CAMERA_TOGGLE = true;
+
     /**
      * Unique Id of this manager to identify to the service
      * @hide
@@ -58,28 +72,39 @@
     public static final String EXTRA_SENSOR = SensorPrivacyManager.class.getName()
             + ".extra.sensor";
 
-    /** Microphone
-     * @hide */
-    @TestApi
-    public static final int INDIVIDUAL_SENSOR_MICROPHONE =
-            SensorPrivacyIndividualEnabledSensorProto.MICROPHONE;
-
-    /** Camera
-     * @hide */
-    @TestApi
-    public static final int INDIVIDUAL_SENSOR_CAMERA =
-            SensorPrivacyIndividualEnabledSensorProto.CAMERA;
-
     /**
-     * Individual sensors not listed in {@link Sensor}
+     * Individual sensors not listed in {@link Sensors}
      * @hide
      */
-    @IntDef(prefix = "INDIVIDUAL_SENSOR_", value = {
-            INDIVIDUAL_SENSOR_MICROPHONE,
-            INDIVIDUAL_SENSOR_CAMERA
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface IndividualSensor {}
+    @SystemApi
+    @TestApi
+    public static class Sensors {
+
+        private Sensors() {}
+
+        /** Microphone
+         * @hide */
+        @SystemApi
+        @TestApi
+        public static final int MICROPHONE = SensorPrivacyIndividualEnabledSensorProto.MICROPHONE;
+        /** Camera
+         * @hide */
+        @SystemApi
+        @TestApi
+        public static final int CAMERA = SensorPrivacyIndividualEnabledSensorProto.CAMERA;
+
+        /**
+         * Individual sensors not listed in {@link Sensors}
+         *
+         * @hide
+         */
+        @IntDef(value = {
+                MICROPHONE,
+                CAMERA
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface Sensor {}
+    }
 
     /**
      * A class implementing this interface can register with the {@link
@@ -88,6 +113,8 @@
      *
      * @hide
      */
+    @SystemApi
+    @TestApi
     public interface OnSensorPrivacyChangedListener {
         /**
          * Callback invoked when the sensor privacy state changes.
@@ -165,7 +192,8 @@
      *
      * @hide
      */
-    public void addSensorPrivacyListener(final OnSensorPrivacyChangedListener listener) {
+    @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY)
+    public void addSensorPrivacyListener(@NonNull final OnSensorPrivacyChangedListener listener) {
         synchronized (mListeners) {
             ISensorPrivacyListener iListener = mListeners.get(listener);
             if (iListener == null) {
@@ -196,15 +224,37 @@
      *
      * @hide
      */
-    public void addSensorPrivacyListener(@IndividualSensor int sensor,
-            final OnSensorPrivacyChangedListener listener) {
+    @SystemApi
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY)
+    public void addSensorPrivacyListener(@Sensors.Sensor int sensor,
+            @NonNull OnSensorPrivacyChangedListener listener) {
+        addSensorPrivacyListener(sensor, mContext.getMainExecutor(), listener);
+    }
+
+    /**
+     * Registers a new listener to receive notification when the state of sensor privacy
+     * changes.
+     *
+     * @param sensor the sensor to listen to changes to
+     * @param executor the executor to dispatch the callback on
+     * @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor
+     *                 privacy changes.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY)
+    public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @NonNull Executor executor,
+            @NonNull OnSensorPrivacyChangedListener listener) {
         synchronized (mListeners) {
             ISensorPrivacyListener iListener = mListeners.get(listener);
             if (iListener == null) {
                 iListener = new ISensorPrivacyListener.Stub() {
                     @Override
                     public void onSensorPrivacyChanged(boolean enabled) {
-                        listener.onSensorPrivacyChanged(enabled);
+                        executor.execute(() -> listener.onSensorPrivacyChanged(enabled));
                     }
                 };
                 mListeners.put(listener, iListener);
@@ -228,7 +278,10 @@
      *
      * @hide
      */
-    public void removeSensorPrivacyListener(OnSensorPrivacyChangedListener listener) {
+    @SystemApi
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY)
+    public void removeSensorPrivacyListener(@NonNull OnSensorPrivacyChangedListener listener) {
         synchronized (mListeners) {
             ISensorPrivacyListener iListener = mListeners.get(listener);
             if (iListener != null) {
@@ -249,6 +302,7 @@
      *
      * @hide
      */
+    @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY)
     public boolean isSensorPrivacyEnabled() {
         try {
             return mService.isSensorPrivacyEnabled();
@@ -264,8 +318,10 @@
      *
      * @hide
      */
+    @SystemApi
     @TestApi
-    public boolean isIndividualSensorPrivacyEnabled(@IndividualSensor int sensor) {
+    @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY)
+    public boolean isSensorPrivacyEnabled(@Sensors.Sensor int sensor) {
         try {
             return mService.isIndividualSensorPrivacyEnabled(mContext.getUserId(), sensor);
         } catch (RemoteException e) {
@@ -283,8 +339,7 @@
      */
     @TestApi
     @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY)
-    public void setIndividualSensorPrivacy(@IndividualSensor int sensor,
-            boolean enable) {
+    public void setSensorPrivacy(@Sensors.Sensor int sensor, boolean enable) {
         try {
             mService.setIndividualSensorPrivacy(mContext.getUserId(), sensor, enable);
         } catch (RemoteException e) {
@@ -303,7 +358,7 @@
      */
     @TestApi
     @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY)
-    public void setIndividualSensorPrivacyForProfileGroup(@IndividualSensor int sensor,
+    public void setSensorPrivacyForProfileGroup(@Sensors.Sensor int sensor,
             boolean enable) {
         try {
             mService.setIndividualSensorPrivacyForProfileGroup(mContext.getUserId(), sensor,
@@ -321,7 +376,8 @@
      *
      * @hide
      */
-    public void suppressIndividualSensorPrivacyReminders(@NonNull String packageName,
+    @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY)
+    public void suppressSensorPrivacyReminders(@NonNull String packageName,
             boolean suppress) {
         try {
             mService.suppressIndividualSensorPrivacyReminders(mContext.getUserId(), packageName,
diff --git a/core/java/android/hardware/devicestate/DeviceStateInfo.aidl b/core/java/android/hardware/devicestate/DeviceStateInfo.aidl
new file mode 100644
index 0000000..e856792
--- /dev/null
+++ b/core/java/android/hardware/devicestate/DeviceStateInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.devicestate;
+
+parcelable DeviceStateInfo;
diff --git a/core/java/android/hardware/devicestate/DeviceStateInfo.java b/core/java/android/hardware/devicestate/DeviceStateInfo.java
new file mode 100644
index 0000000..bc6af37
--- /dev/null
+++ b/core/java/android/hardware/devicestate/DeviceStateInfo.java
@@ -0,0 +1,162 @@
+/*
+ * 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.devicestate;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+
+/**
+ * Information about the state of the device.
+ *
+ * @hide
+ */
+public final class DeviceStateInfo implements Parcelable {
+    /** Bit that indicates the {@link #supportedStates} field has changed. */
+    public static final int CHANGED_SUPPORTED_STATES = 1 << 0;
+
+    /** Bit that indicates the {@link #baseState} field has changed. */
+    public static final int CHANGED_BASE_STATE = 1 << 1;
+
+    /** Bit that indicates the {@link #currentState} field has changed. */
+    public static final int CHANGED_CURRENT_STATE = 1 << 2;
+
+    @IntDef(prefix = {"CHANGED_"}, flag = true, value = {
+            CHANGED_SUPPORTED_STATES,
+            CHANGED_BASE_STATE,
+            CHANGED_CURRENT_STATE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ChangeFlags {}
+
+    /**
+     * The list of states supported by the device.
+     */
+    @NonNull
+    public final int[] supportedStates;
+
+    /**
+     * The base (non-override) state of the device. The base state is the state of the device
+     * ignoring any override requests made through a call to {@link DeviceStateManager#requestState(
+     * DeviceStateRequest, Executor, DeviceStateRequest.Callback)}.
+     */
+    public final int baseState;
+
+    /**
+     * The state of the device.
+     */
+    public final int currentState;
+
+    /**
+     * Creates a new instance of {@link DeviceStateInfo}.
+     * <p>
+     * NOTE: Unlike {@link #DeviceStateInfo(DeviceStateInfo)}, this constructor does not copy the
+     * supplied parameters.
+     */
+    public DeviceStateInfo(@NonNull int[] supportedStates, int baseState, int state) {
+        this.supportedStates = supportedStates;
+        this.baseState = baseState;
+        this.currentState = state;
+    }
+
+    /**
+     * Creates a new instance of {@link DeviceStateInfo} copying the fields of {@code info} into
+     * the fields of the returned instance.
+     */
+    public DeviceStateInfo(@NonNull DeviceStateInfo info) {
+        this(Arrays.copyOf(info.supportedStates, info.supportedStates.length),
+                info.baseState, info.currentState);
+    }
+
+    @Override
+    public boolean equals(@Nullable Object other) {
+        if (this == other) return true;
+        if (other == null || getClass() != other.getClass()) return false;
+        DeviceStateInfo that = (DeviceStateInfo) other;
+        return baseState == that.baseState
+                &&  currentState == that.currentState
+                && Arrays.equals(supportedStates, that.supportedStates);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = Objects.hash(baseState, currentState);
+        result = 31 * result + Arrays.hashCode(supportedStates);
+        return result;
+    }
+
+    /** Returns a bitmask of the differences between this instance and {@code other}. */
+    @ChangeFlags
+    public int diff(@NonNull DeviceStateInfo other) {
+        int diff = 0;
+        if (!Arrays.equals(supportedStates, other.supportedStates)) {
+            diff |= CHANGED_SUPPORTED_STATES;
+        }
+        if (baseState != other.baseState) {
+            diff |= CHANGED_BASE_STATE;
+        }
+        if (currentState != other.currentState) {
+            diff |= CHANGED_CURRENT_STATE;
+        }
+        return diff;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(supportedStates.length);
+        for (int i = 0; i < supportedStates.length; i++) {
+            dest.writeInt(supportedStates[i]);
+        }
+
+        dest.writeInt(baseState);
+        dest.writeInt(currentState);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final @NonNull Creator<DeviceStateInfo> CREATOR = new Creator<DeviceStateInfo>() {
+        @Override
+        public DeviceStateInfo createFromParcel(Parcel source) {
+            final int numberOfSupportedStates = source.readInt();
+            final int[] supportedStates = new int[numberOfSupportedStates];
+            for (int i = 0; i < numberOfSupportedStates; i++) {
+                supportedStates[i] = source.readInt();
+            }
+            final int baseState = source.readInt();
+            final int currentState = source.readInt();
+
+            return new DeviceStateInfo(supportedStates, baseState, currentState);
+        }
+
+        @Override
+        public DeviceStateInfo[] newArray(int size) {
+            return new DeviceStateInfo[size];
+        }
+    };
+}
diff --git a/core/java/android/hardware/devicestate/DeviceStateManager.java b/core/java/android/hardware/devicestate/DeviceStateManager.java
index 2d4b2cc..250145e 100644
--- a/core/java/android/hardware/devicestate/DeviceStateManager.java
+++ b/core/java/android/hardware/devicestate/DeviceStateManager.java
@@ -111,38 +111,63 @@
     }
 
     /**
-     * Registers a listener to receive notifications about changes in device state.
+     * Registers a callback to receive notifications about changes in device state.
      *
      * @param executor the executor to process notifications.
-     * @param listener the listener to register.
+     * @param callback the callback to register.
      *
-     * @see DeviceStateListener
+     * @see DeviceStateCallback
      */
-    public void addDeviceStateListener(@NonNull @CallbackExecutor Executor executor,
-            @NonNull DeviceStateListener listener) {
-        mGlobal.registerDeviceStateListener(listener, executor);
+    public void registerCallback(@NonNull @CallbackExecutor Executor executor,
+            @NonNull DeviceStateCallback callback) {
+        mGlobal.registerDeviceStateCallback(callback, executor);
     }
 
     /**
-     * Unregisters a listener previously registered with
-     * {@link #addDeviceStateListener(Executor, DeviceStateListener)}.
+     * Unregisters a callback previously registered with
+     * {@link #registerCallback(Executor, DeviceStateCallback)}.
      */
-    public void removeDeviceStateListener(@NonNull DeviceStateListener listener) {
-        mGlobal.unregisterDeviceStateListener(listener);
+    public void unregisterCallback(@NonNull DeviceStateCallback callback) {
+        mGlobal.unregisterDeviceStateCallback(callback);
     }
 
-    /**
-     * Listens for changes in device states.
-     */
-    public interface DeviceStateListener {
+    /** Callback to receive notifications about changes in device state. */
+    public interface DeviceStateCallback {
+        /**
+         * Called in response to a change in the states supported by the device.
+         * <p>
+         * Guaranteed to be called once on registration of the callback with the initial value and
+         * then on every subsequent change in the supported states.
+         *
+         * @param supportedStates the new supported states.
+         *
+         * @see DeviceStateManager#getSupportedStates()
+         */
+        default void onSupportedStatesChanged(@NonNull int[] supportedStates) {}
+
+        /**
+         * Called in response to a change in the base device state.
+         * <p>
+         * The base state is the state of the device without considering any requests made through
+         * calls to {@link #requestState(DeviceStateRequest, Executor, DeviceStateRequest.Callback)}
+         * from any client process. The base state is guaranteed to match the state provided with a
+         * call to {@link #onStateChanged(int)} when there are no active requests from any process.
+         * <p>
+         * Guaranteed to be called once on registration of the callback with the initial value and
+         * then on every subsequent change in the non-override state.
+         *
+         * @param state the new base device state.
+         */
+        default void onBaseStateChanged(int state) {}
+
         /**
          * Called in response to device state changes.
          * <p>
-         * Guaranteed to be called once on registration of the listener with the
-         * initial value and then on every subsequent change in device state.
+         * Guaranteed to be called once on registration of the callback with the initial value and
+         * then on every subsequent change in device state.
          *
-         * @param deviceState the new device state.
+         * @param state the new device state.
          */
-        void onDeviceStateChanged(int deviceState);
+        void onStateChanged(int state);
     }
 }
diff --git a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
index b9ae88e..1b37fb9 100644
--- a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
+++ b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
@@ -19,7 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
-import android.hardware.devicestate.DeviceStateManager.DeviceStateListener;
+import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -31,12 +31,14 @@
 import com.android.internal.annotations.VisibleForTesting.Visibility;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.concurrent.Executor;
 
 /**
  * Provides communication with the device state system service on behalf of applications.
  *
  * @see DeviceStateManager
+ *
  * @hide
  */
 @VisibleForTesting(visibility = Visibility.PACKAGE)
@@ -68,13 +70,13 @@
     private DeviceStateManagerCallback mCallback;
 
     @GuardedBy("mLock")
-    private final ArrayList<DeviceStateListenerWrapper> mListeners = new ArrayList<>();
+    private final ArrayList<DeviceStateCallbackWrapper> mCallbacks = new ArrayList<>();
     @GuardedBy("mLock")
     private final ArrayMap<IBinder, DeviceStateRequestWrapper> mRequests = new ArrayMap<>();
 
     @Nullable
     @GuardedBy("mLock")
-    private Integer mLastReceivedState;
+    private DeviceStateInfo mLastReceivedInfo;
 
     @VisibleForTesting
     public DeviceStateManagerGlobal(@NonNull IDeviceStateManager deviceStateManager) {
@@ -87,18 +89,31 @@
      * @see DeviceStateManager#getSupportedStates()
      */
     public int[] getSupportedStates() {
-        try {
-            return mDeviceStateManager.getSupportedDeviceStates();
-        } catch (RemoteException ex) {
-            throw ex.rethrowFromSystemServer();
+        synchronized (mLock) {
+            final DeviceStateInfo currentInfo;
+            if (mLastReceivedInfo != null) {
+                // If we have mLastReceivedInfo a callback is registered for this instance and it
+                // is receiving the most recent info from the server. Use that info here.
+                currentInfo = mLastReceivedInfo;
+            } else {
+                // If mLastReceivedInfo is null there is no registered callback so we manually
+                // fetch the current info.
+                try {
+                    currentInfo = mDeviceStateManager.getDeviceStateInfo();
+                } catch (RemoteException ex) {
+                    throw ex.rethrowFromSystemServer();
+                }
+            }
+
+            return Arrays.copyOf(currentInfo.supportedStates, currentInfo.supportedStates.length);
         }
     }
 
     /**
      * Submits a {@link DeviceStateRequest request} to modify the device state.
      *
-     * @see DeviceStateManager#requestState(DeviceStateRequest,
-     * Executor, DeviceStateRequest.Callback)
+     * @see DeviceStateManager#requestState(DeviceStateRequest, Executor,
+     * DeviceStateRequest.Callback)
      * @see DeviceStateRequest
      */
     public void requestState(@NonNull DeviceStateRequest request,
@@ -157,49 +172,56 @@
     }
 
     /**
-     * Registers a listener to receive notifications about changes in device state.
+     * Registers a callback to receive notifications about changes in device state.
      *
-     * @see DeviceStateManager#addDeviceStateListener(Executor, DeviceStateListener)
+     * @see DeviceStateManager#registerCallback(Executor, DeviceStateCallback)
      */
     @VisibleForTesting(visibility = Visibility.PACKAGE)
-    public void registerDeviceStateListener(@NonNull DeviceStateListener listener,
+    public void registerDeviceStateCallback(@NonNull DeviceStateCallback callback,
             @NonNull Executor executor) {
-        Integer stateToReport;
-        DeviceStateListenerWrapper wrapper;
+        DeviceStateCallbackWrapper wrapper;
+        DeviceStateInfo currentInfo;
         synchronized (mLock) {
-            registerCallbackIfNeededLocked();
-
-            int index = findListenerLocked(listener);
+            int index = findCallbackLocked(callback);
             if (index != -1) {
-                // This listener is already registered.
+                // This callback is already registered.
                 return;
             }
 
-            wrapper = new DeviceStateListenerWrapper(listener, executor);
-            mListeners.add(wrapper);
-            stateToReport = mLastReceivedState;
+            registerCallbackIfNeededLocked();
+            if (mLastReceivedInfo == null) {
+                // Initialize the last received info with the current info if this is the first
+                // callback being registered.
+                try {
+                    mLastReceivedInfo = mDeviceStateManager.getDeviceStateInfo();
+                } catch (RemoteException ex) {
+                    throw ex.rethrowFromSystemServer();
+                }
+            }
+
+            currentInfo = new DeviceStateInfo(mLastReceivedInfo);
+
+            wrapper = new DeviceStateCallbackWrapper(callback, executor);
+            mCallbacks.add(wrapper);
         }
 
-        if (stateToReport != null) {
-            // Notify the listener with the most recent device state from the server. If the state
-            // to report is null this is likely the first listener added and we're still waiting
-            // from the callback from the server.
-            wrapper.notifyDeviceStateChanged(stateToReport);
-        }
+        wrapper.notifySupportedStatesChanged(currentInfo.supportedStates);
+        wrapper.notifyBaseStateChanged(currentInfo.baseState);
+        wrapper.notifyStateChanged(currentInfo.currentState);
     }
 
     /**
-     * Unregisters a listener previously registered with
-     * {@link #registerDeviceStateListener(DeviceStateListener, Executor)}.
+     * Unregisters a callback previously registered with
+     * {@link #registerDeviceStateCallback(DeviceStateCallback, Executor)}}.
      *
-     * @see DeviceStateManager#addDeviceStateListener(Executor, DeviceStateListener)
+     * @see DeviceStateManager#unregisterCallback(DeviceStateCallback)
      */
     @VisibleForTesting(visibility = Visibility.PACKAGE)
-    public void unregisterDeviceStateListener(DeviceStateListener listener) {
+    public void unregisterDeviceStateCallback(@NonNull DeviceStateCallback callback) {
         synchronized (mLock) {
-            int indexToRemove = findListenerLocked(listener);
+            int indexToRemove = findCallbackLocked(callback);
             if (indexToRemove != -1) {
-                mListeners.remove(indexToRemove);
+                mCallbacks.remove(indexToRemove);
             }
         }
     }
@@ -210,14 +232,15 @@
             try {
                 mDeviceStateManager.registerCallback(mCallback);
             } catch (RemoteException ex) {
+                mCallback = null;
                 throw ex.rethrowFromSystemServer();
             }
         }
     }
 
-    private int findListenerLocked(DeviceStateListener listener) {
-        for (int i = 0; i < mListeners.size(); i++) {
-            if (mListeners.get(i).mDeviceStateListener.equals(listener)) {
+    private int findCallbackLocked(DeviceStateCallback callback) {
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            if (mCallbacks.get(i).mDeviceStateCallback.equals(callback)) {
                 return i;
             }
         }
@@ -234,16 +257,34 @@
         return null;
     }
 
-    /** Handles a call from the server that the device state has changed. */
-    private void handleDeviceStateChanged(int newDeviceState) {
-        ArrayList<DeviceStateListenerWrapper> listeners;
+    /** Handles a call from the server that the device state info has changed. */
+    private void handleDeviceStateInfoChanged(@NonNull DeviceStateInfo info) {
+        ArrayList<DeviceStateCallbackWrapper> callbacks;
+        DeviceStateInfo oldInfo;
         synchronized (mLock) {
-            mLastReceivedState = newDeviceState;
-            listeners = new ArrayList<>(mListeners);
+            oldInfo = mLastReceivedInfo;
+            mLastReceivedInfo = info;
+            callbacks = new ArrayList<>(mCallbacks);
         }
 
-        for (int i = 0; i < listeners.size(); i++) {
-            listeners.get(i).notifyDeviceStateChanged(newDeviceState);
+        final int diff = oldInfo == null ? 1 : info.diff(oldInfo);
+        if ((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0) {
+            for (int i = 0; i < callbacks.size(); i++) {
+                // Copy the array to prevent callbacks from modifying the internal state.
+                final int[] supportedStates = Arrays.copyOf(info.supportedStates,
+                        info.supportedStates.length);
+                callbacks.get(i).notifySupportedStatesChanged(supportedStates);
+            }
+        }
+        if ((diff & DeviceStateInfo.CHANGED_BASE_STATE) > 0) {
+            for (int i = 0; i < callbacks.size(); i++) {
+                callbacks.get(i).notifyBaseStateChanged(info.baseState);
+            }
+        }
+        if ((diff & DeviceStateInfo.CHANGED_CURRENT_STATE) > 0) {
+            for (int i = 0; i < callbacks.size(); i++) {
+                callbacks.get(i).notifyStateChanged(info.currentState);
+            }
         }
     }
 
@@ -291,8 +332,8 @@
 
     private final class DeviceStateManagerCallback extends IDeviceStateManagerCallback.Stub {
         @Override
-        public void onDeviceStateChanged(int deviceState) {
-            handleDeviceStateChanged(deviceState);
+        public void onDeviceStateInfoChanged(DeviceStateInfo info) {
+            handleDeviceStateInfoChanged(info);
         }
 
         @Override
@@ -311,17 +352,29 @@
         }
     }
 
-    private static final class DeviceStateListenerWrapper {
-        private final DeviceStateListener mDeviceStateListener;
+    private static final class DeviceStateCallbackWrapper {
+        @NonNull
+        private final DeviceStateCallback mDeviceStateCallback;
+        @NonNull
         private final Executor mExecutor;
 
-        DeviceStateListenerWrapper(DeviceStateListener listener, Executor executor) {
-            mDeviceStateListener = listener;
+        DeviceStateCallbackWrapper(@NonNull DeviceStateCallback callback,
+                @NonNull Executor executor) {
+            mDeviceStateCallback = callback;
             mExecutor = executor;
         }
 
-        void notifyDeviceStateChanged(int newDeviceState) {
-            mExecutor.execute(() -> mDeviceStateListener.onDeviceStateChanged(newDeviceState));
+        void notifySupportedStatesChanged(int[] newSupportedStates) {
+            mExecutor.execute(() ->
+                    mDeviceStateCallback.onSupportedStatesChanged(newSupportedStates));
+        }
+
+        void notifyBaseStateChanged(int newBaseState) {
+            mExecutor.execute(() -> mDeviceStateCallback.onBaseStateChanged(newBaseState));
+        }
+
+        void notifyStateChanged(int newDeviceState) {
+            mExecutor.execute(() -> mDeviceStateCallback.onStateChanged(newDeviceState));
         }
     }
 
diff --git a/core/java/android/hardware/devicestate/DeviceStateRequest.java b/core/java/android/hardware/devicestate/DeviceStateRequest.java
index 70f7002..df488d2 100644
--- a/core/java/android/hardware/devicestate/DeviceStateRequest.java
+++ b/core/java/android/hardware/devicestate/DeviceStateRequest.java
@@ -116,7 +116,7 @@
          * requested state.
          * <p>
          * Guaranteed to be called after a call to
-         * {@link DeviceStateManager.DeviceStateListener#onDeviceStateChanged(int)} with a state
+         * {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)} with a state
          * matching the requested state.
          */
         default void onRequestActivated(@NonNull DeviceStateRequest request) {}
@@ -125,7 +125,7 @@
          * Called to indicate the request has been temporarily suspended.
          * <p>
          * Guaranteed to be called before a call to
-         * {@link DeviceStateManager.DeviceStateListener#onDeviceStateChanged(int)}.
+         * {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)}.
          */
         default void onRequestSuspended(@NonNull DeviceStateRequest request) {}
 
@@ -135,7 +135,7 @@
          * DeviceStateRequest.Callback)}.
          * <p>
          * Guaranteed to be called before a call to
-         * {@link DeviceStateManager.DeviceStateListener#onDeviceStateChanged(int)}.
+         * {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)}.
          * <p>
          * Note: A call to {@link #onRequestSuspended(DeviceStateRequest)} is not guaranteed to
          * occur before this method.
diff --git a/core/java/android/hardware/devicestate/IDeviceStateManager.aidl b/core/java/android/hardware/devicestate/IDeviceStateManager.aidl
index 323ad21..14ed03d 100644
--- a/core/java/android/hardware/devicestate/IDeviceStateManager.aidl
+++ b/core/java/android/hardware/devicestate/IDeviceStateManager.aidl
@@ -16,25 +16,26 @@
 
 package android.hardware.devicestate;
 
+import android.hardware.devicestate.DeviceStateInfo;
 import android.hardware.devicestate.IDeviceStateManagerCallback;
 
 /** @hide */
 interface IDeviceStateManager {
+    /** Returns the current device state info. */
+    DeviceStateInfo getDeviceStateInfo();
+
     /**
      * Registers a callback to receive notifications from the device state manager. Only one
      * callback can be registered per-process.
      * <p>
      * As the callback mechanism is used to alert the caller of changes to request status a callback
      * <b>MUST</b> be registered before calling {@link #requestState(IBinder, int, int)} or
-     * {@link #cancelRequest(IBinder)}. Otherwise an exception will be thrown.
+     * {@link #cancelRequest(IBinder)}, otherwise an exception will be thrown.
      *
      * @throws SecurityException if a callback is already registered for the calling process.
      */
     void registerCallback(in IDeviceStateManagerCallback callback);
 
-    /** Returns the array of supported device state identifiers. */
-    int[] getSupportedDeviceStates();
-
     /**
      * Requests that the device enter the supplied {@code state}. A callback <b>MUST</b> have been
      * previously registered with {@link #registerCallback(IDeviceStateManagerCallback)} before a
diff --git a/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl b/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl
index ee2a071..593be86 100644
--- a/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl
+++ b/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl
@@ -16,20 +16,23 @@
 
 package android.hardware.devicestate;
 
+import android.hardware.devicestate.DeviceStateInfo;
+
 /** @hide */
 interface IDeviceStateManagerCallback {
     /**
-     * Called in response to a change in device state. Guaranteed to be called once with the initial
-     * value on registration of the callback.
+     * Called in response to a change in {@link DeviceStateInfo}.
      *
-     * @param deviceState the new state of the device.
+     * @param info the new device state info.
+     *
+     * @see DeviceStateInfo
      */
-    oneway void onDeviceStateChanged(int deviceState);
+    oneway void onDeviceStateInfoChanged(in DeviceStateInfo info);
 
     /**
      * Called to notify the callback that a request has become active. Guaranteed to be called
-     * after a subsequent call to {@link #onDeviceStateChanged(int)} if the request becoming active
-     * resulted in a device state change.
+     * after a subsequent call to {@link #onDeviceStateInfoChanged(DeviceStateInfo)} if the request
+     * becoming active resulted in a change of device state info.
      *
      * @param token the request token previously registered with
      *        {@link IDeviceStateManager#requestState(IBinder, int, int)}
@@ -38,8 +41,8 @@
 
     /**
      * Called to notify the callback that a request has become suspended. Guaranteed to be called
-     * before a subsequent call to {@link #onDeviceStateChanged(int)} if the request becoming
-     * suspended resulted in a device state change.
+     * before a subsequent call to {@link #onDeviceStateInfoChanged(DeviceStateInfo)} if the request
+     * becoming suspended resulted in a change of device state info.
      *
      * @param token the request token previously registered with
      *        {@link IDeviceStateManager#requestState(IBinder, int, int)}
@@ -49,8 +52,8 @@
     /**
      * Called to notify the callback that a request has become canceled. No further callbacks will
      * be triggered for this request. Guaranteed to be called before a subsequent call to
-     * {@link #onDeviceStateChanged(int)} if the request becoming canceled resulted in a device
-     * state change.
+     * {@link #onDeviceStateInfoChanged(DeviceStateInfo)} if the request becoming canceled resulted
+     * in a change of device state info.
      *
      * @param token the request token previously registered with
      *        {@link IDeviceStateManager#requestState(IBinder, int, int)}
diff --git a/core/java/android/hardware/display/ColorDisplayManager.java b/core/java/android/hardware/display/ColorDisplayManager.java
index e247df3..aafa7d5 100644
--- a/core/java/android/hardware/display/ColorDisplayManager.java
+++ b/core/java/android/hardware/display/ColorDisplayManager.java
@@ -537,6 +537,26 @@
     }
 
     /**
+     * Returns the minimum allowed brightness reduction strength in percentage when activated.
+     *
+     * @hide
+     */
+    public static int getMinimumReduceBrightColorsStrength(Context context) {
+        return context.getResources()
+                .getInteger(R.integer.config_reduceBrightColorsStrengthMin);
+    }
+
+    /**
+     * Returns the maximum allowed brightness reduction strength in percentage when activated.
+     *
+     * @hide
+     */
+    public static int getMaximumReduceBrightColorsStrength(Context context) {
+        return context.getResources()
+                .getInteger(R.integer.config_reduceBrightColorsStrengthMax);
+    }
+
+    /**
      * Check if the color transforms are color accelerated. Some transforms are experimental only
      * on non-accelerated platforms due to the performance implications.
      *
diff --git a/core/java/android/hardware/display/DeviceProductInfo.java b/core/java/android/hardware/display/DeviceProductInfo.java
index 41126b7..9457d8f1 100644
--- a/core/java/android/hardware/display/DeviceProductInfo.java
+++ b/core/java/android/hardware/display/DeviceProductInfo.java
@@ -16,40 +16,69 @@
 
 package android.hardware.display;
 
+import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import java.util.Arrays;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
 
 /**
  * Product-specific information about the display or the directly connected device on the
  * display chain. For example, if the display is transitively connected, this field may contain
  * product information about the intermediate device.
- * @hide
  */
 public final class DeviceProductInfo implements Parcelable {
+    /** @hide */
+    @IntDef(prefix = {"CONNECTION_TO_SINK_"}, value = {
+            CONNECTION_TO_SINK_UNKNOWN,
+            CONNECTION_TO_SINK_BUILT_IN,
+            CONNECTION_TO_SINK_DIRECT,
+            CONNECTION_TO_SINK_TRANSITIVE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ConnectionToSinkType { }
+
+    /** The device connection to the display sink is unknown. */
+    public static final int CONNECTION_TO_SINK_UNKNOWN =
+            IDeviceProductInfoConstants.CONNECTION_TO_SINK_UNKNOWN;
+
+    /** The display sink is built-in to the device */
+    public static final int CONNECTION_TO_SINK_BUILT_IN =
+            IDeviceProductInfoConstants.CONNECTION_TO_SINK_BUILT_IN;
+
+    /** The device is directly connected to the display sink. */
+    public static final int CONNECTION_TO_SINK_DIRECT =
+            IDeviceProductInfoConstants.CONNECTION_TO_SINK_DIRECT;
+
+    /** The device is transitively connected to the display sink. */
+    public static final int CONNECTION_TO_SINK_TRANSITIVE =
+            IDeviceProductInfoConstants.CONNECTION_TO_SINK_TRANSITIVE;
+
     private final String mName;
     private final String mManufacturerPnpId;
     private final String mProductId;
     private final Integer mModelYear;
     private final ManufactureDate mManufactureDate;
-    private final int[] mRelativeAddress;
+    private final @ConnectionToSinkType int mConnectionToSinkType;
 
+    /** @hide */
     public DeviceProductInfo(
             String name,
             String manufacturerPnpId,
             String productId,
             Integer modelYear,
             ManufactureDate manufactureDate,
-            int[] relativeAddress) {
+            int connectionToSinkType) {
         this.mName = name;
         this.mManufacturerPnpId = manufacturerPnpId;
         this.mProductId = productId;
         this.mModelYear = modelYear;
         this.mManufactureDate = manufactureDate;
-        this.mRelativeAddress = relativeAddress;
+        this.mConnectionToSinkType = connectionToSinkType;
     }
 
     private DeviceProductInfo(Parcel in) {
@@ -58,12 +87,13 @@
         mProductId = (String) in.readValue(null);
         mModelYear = (Integer) in.readValue(null);
         mManufactureDate = (ManufactureDate) in.readValue(null);
-        mRelativeAddress = in.createIntArray();
+        mConnectionToSinkType = in.readInt();
     }
 
     /**
      * @return Display name.
      */
+    @Nullable
     public String getName() {
         return mName;
     }
@@ -71,6 +101,7 @@
     /**
      * @return Manufacturer Plug and Play ID.
      */
+    @NonNull
     public String getManufacturerPnpId() {
         return mManufacturerPnpId;
     }
@@ -78,32 +109,58 @@
     /**
      * @return Manufacturer product ID.
      */
+    @NonNull
     public String getProductId() {
         return mProductId;
     }
 
     /**
-     * @return Model year of the device. Typically exactly one of model year or
-     *      manufacture date will be present.
+     * @return Model year of the device. Return -1 if not available. Typically,
+     * one of model year or manufacture year is available.
      */
-    public Integer getModelYear() {
-        return mModelYear;
+    public int getModelYear()  {
+        return mModelYear != null ? mModelYear : -1;
+    }
+
+    /**
+     * @return The year of manufacture, or -1 it is not available. Typically,
+     * one of model year or manufacture year is available.
+     */
+    public int getManufactureYear()  {
+        if (mManufactureDate == null) {
+            return -1;
+        }
+        return mManufactureDate.mYear != null ? mManufactureDate.mYear : -1;
+    }
+
+    /**
+     * @return The week of manufacture, or -1 it is not available. Typically,
+     * not present if model year is available.
+     */
+    public int getManufactureWeek() {
+        if (mManufactureDate == null) {
+            return -1;
+        }
+        return mManufactureDate.mWeek != null ?  mManufactureDate.mWeek : -1;
     }
 
     /**
      * @return Manufacture date. Typically exactly one of model year or manufacture
      * date will be present.
+     *
+     * @hide
      */
     public ManufactureDate getManufactureDate() {
         return mManufactureDate;
     }
 
     /**
-     * @return Relative address in the display network. For example, for HDMI connected devices this
-     * can be its physical address. Each component of the address is in the range [0, 255].
+     * @return How the current device is connected to the display sink. For example, the display
+     * can be connected immediately to the device or there can be a receiver in between.
      */
-    public int[] getRelativeAddress() {
-        return mRelativeAddress;
+    @ConnectionToSinkType
+    public int getConnectionToSinkType() {
+        return mConnectionToSinkType;
     }
 
     @Override
@@ -119,8 +176,8 @@
                 + mModelYear
                 + ", manufactureDate="
                 + mManufactureDate
-                + ", relativeAddress="
-                + Arrays.toString(mRelativeAddress)
+                + ", connectionToSinkType="
+                + mConnectionToSinkType
                 + '}';
     }
 
@@ -134,16 +191,16 @@
                 && Objects.equals(mProductId, that.mProductId)
                 && Objects.equals(mModelYear, that.mModelYear)
                 && Objects.equals(mManufactureDate, that.mManufactureDate)
-                && Arrays.equals(mRelativeAddress, that.mRelativeAddress);
+                && mConnectionToSinkType == that.mConnectionToSinkType;
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(mName, mManufacturerPnpId, mProductId, mModelYear, mManufactureDate,
-            Arrays.hashCode(mRelativeAddress));
+                mConnectionToSinkType);
     }
 
-    public static final Creator<DeviceProductInfo> CREATOR =
+    @NonNull public static final Creator<DeviceProductInfo> CREATOR =
             new Creator<DeviceProductInfo>() {
                 @Override
                 public DeviceProductInfo createFromParcel(Parcel in) {
@@ -162,13 +219,13 @@
     }
 
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeString(mName);
         dest.writeString(mManufacturerPnpId);
         dest.writeValue(mProductId);
         dest.writeValue(mModelYear);
         dest.writeValue(mManufactureDate);
-        dest.writeIntArray(mRelativeAddress);
+        dest.writeInt(mConnectionToSinkType);
     }
 
     /**
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index f66ecdf..0256b7b 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -1392,7 +1392,7 @@
             case FACE_ACQUIRED_PAN_TOO_EXTREME:
             case FACE_ACQUIRED_TILT_TOO_EXTREME:
             case FACE_ACQUIRED_ROLL_TOO_EXTREME:
-                return context.getString(R.string.face_acquired_not_detected);
+                return context.getString(R.string.face_acquired_poor_gaze);
 
             // Provide more detailed feedback for other soft errors.
             case FACE_ACQUIRED_INSUFFICIENT:
@@ -1448,13 +1448,17 @@
             case FACE_ACQUIRED_TOO_FAR:
                 return context.getString(R.string.face_acquired_too_far);
             case FACE_ACQUIRED_TOO_HIGH:
-                return context.getString(R.string.face_acquired_too_high);
-            case FACE_ACQUIRED_TOO_LOW:
+                // TODO(b/181269243): Change back once error codes are fixed.
                 return context.getString(R.string.face_acquired_too_low);
+            case FACE_ACQUIRED_TOO_LOW:
+                // TODO(b/181269243) Change back once error codes are fixed.
+                return context.getString(R.string.face_acquired_too_high);
             case FACE_ACQUIRED_TOO_RIGHT:
-                return context.getString(R.string.face_acquired_too_right);
-            case FACE_ACQUIRED_TOO_LEFT:
+                // TODO(b/181269243) Change back once error codes are fixed.
                 return context.getString(R.string.face_acquired_too_left);
+            case FACE_ACQUIRED_TOO_LEFT:
+                // TODO(b/181269243) Change back once error codes are fixed.
+                return context.getString(R.string.face_acquired_too_right);
             case FACE_ACQUIRED_POOR_GAZE:
                 return context.getString(R.string.face_acquired_poor_gaze);
             case FACE_ACQUIRED_NOT_DETECTED:
diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
index 663a704..51addc9 100644
--- a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
+++ b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
@@ -85,8 +85,8 @@
             boolean resetLockoutRequiresHardwareAuthToken) {
         // TODO(b/179175438): Value should be provided from the HAL
         this(sensorId, strength, maxEnrollmentsPerUser, sensorType,
-                resetLockoutRequiresHardwareAuthToken, 0 /* sensorLocationX */,
-                0 /* sensorLocationY */, 0 /* sensorRadius */);
+                resetLockoutRequiresHardwareAuthToken, 540 /* sensorLocationX */,
+                1636 /* sensorLocationY */, 130 /* sensorRadius */);
     }
 
     /**
diff --git a/core/java/android/hardware/soundtrigger/ConversionUtil.java b/core/java/android/hardware/soundtrigger/ConversionUtil.java
index 06b5b67..a5c9a7f 100644
--- a/core/java/android/hardware/soundtrigger/ConversionUtil.java
+++ b/core/java/android/hardware/soundtrigger/ConversionUtil.java
@@ -34,10 +34,7 @@
 import android.media.soundtrigger_middleware.SoundTriggerModuleProperties;
 import android.os.ParcelFileDescriptor;
 import android.os.SharedMemory;
-import android.system.ErrnoException;
 
-import java.io.FileDescriptor;
-import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.UUID;
@@ -111,13 +108,9 @@
         aidlModel.type = apiModel.getType();
         aidlModel.uuid = api2aidlUuid(apiModel.getUuid());
         aidlModel.vendorUuid = api2aidlUuid(apiModel.getVendorUuid());
-        try {
-            aidlModel.data = ParcelFileDescriptor.dup(
-                    byteArrayToSharedMemory(apiModel.getData(), "SoundTrigger SoundModel"));
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-        aidlModel.dataSize = apiModel.getData().length;
+        byte[] data = apiModel.getData();
+        aidlModel.data = byteArrayToSharedMemory(data, "SoundTrigger SoundModel");
+        aidlModel.dataSize = data.length;
         return aidlModel;
     }
 
@@ -379,7 +372,7 @@
         return result;
     }
 
-    private static @Nullable FileDescriptor byteArrayToSharedMemory(byte[] data, String name) {
+    private static @Nullable ParcelFileDescriptor byteArrayToSharedMemory(byte[] data, String name) {
         if (data.length == 0) {
             return null;
         }
@@ -389,8 +382,10 @@
             ByteBuffer buffer = shmem.mapReadWrite();
             buffer.put(data);
             shmem.unmap(buffer);
-            return shmem.getFileDescriptor();
-        } catch (ErrnoException e) {
+            ParcelFileDescriptor fd = shmem.getFdDup();
+            shmem.close();
+            return fd;
+        } catch (Exception e) {
             throw new RuntimeException(e);
         }
     }
diff --git a/core/java/android/hardware/soundtrigger/OWNERS b/core/java/android/hardware/soundtrigger/OWNERS
index 816bc6b..e5d0370 100644
--- a/core/java/android/hardware/soundtrigger/OWNERS
+++ b/core/java/android/hardware/soundtrigger/OWNERS
@@ -1 +1,2 @@
-include /core/java/android/media/soundtrigger/OWNERS
+ytai@google.com
+elaurent@google.com
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 9198eb7..5cfcd66 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -171,7 +171,7 @@
                 SomeArgs args = (SomeArgs) msg.obj;
                 try {
                     inputMethod.initializeInternal((IBinder) args.arg1, msg.arg1,
-                            (IInputMethodPrivilegedOperations) args.arg2, (int) args.arg3);
+                            (IInputMethodPrivilegedOperations) args.arg2);
                 } finally {
                     args.recycle();
                 }
@@ -280,10 +280,9 @@
     @BinderThread
     @Override
     public void initializeInternal(IBinder token, int displayId,
-            IInputMethodPrivilegedOperations privOps, int configChanges) {
+            IInputMethodPrivilegedOperations privOps) {
         mCaller.executeOrSendMessage(
-                mCaller.obtainMessageIOOO(DO_INITIALIZE_INTERNAL, displayId, token, privOps,
-                        configChanges));
+                mCaller.obtainMessageIOO(DO_INITIALIZE_INTERNAL, displayId, token, privOps));
     }
 
     @BinderThread
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 03dd306..7e2be01 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -70,7 +70,6 @@
 import android.compat.annotation.EnabledSince;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
-import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -132,7 +131,6 @@
 import android.window.WindowMetricsHelper;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.inputmethod.IInputContentUriToken;
 import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
 import com.android.internal.inputmethod.InputMethodPrivilegedOperations;
@@ -515,8 +513,6 @@
     private boolean mIsAutomotive;
     private Handler mHandler;
     private boolean mImeSurfaceScheduledForRemoval;
-    private Configuration mLastKnownConfig;
-    private int mHandledConfigChanges;
 
     /**
      * An opaque {@link Binder} token of window requesting {@link InputMethodImpl#showSoftInput}
@@ -592,14 +588,12 @@
         @MainThread
         @Override
         public final void initializeInternal(@NonNull IBinder token, int displayId,
-                IInputMethodPrivilegedOperations privilegedOperations,
-                int configChanges) {
+                IInputMethodPrivilegedOperations privilegedOperations) {
             if (InputMethodPrivilegedOperationsRegistry.isRegistered(token)) {
                 Log.w(TAG, "The token has already registered, ignore this initialization.");
                 return;
             }
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initializeInternal");
-            mHandledConfigChanges = configChanges;
             mPrivOps.set(privilegedOperations);
             InputMethodPrivilegedOperationsRegistry.put(token, mPrivOps);
             updateInputMethodDisplay(displayId);
@@ -827,9 +821,6 @@
                 setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
             }
             final boolean isVisible = isInputViewShown();
-            if (isVisible && getResources() != null) {
-                mLastKnownConfig = getResources().getConfiguration();
-            }
             final boolean visibilityChanged = isVisible != wasVisible;
             if (resultReceiver != null) {
                 resultReceiver.send(visibilityChanged
@@ -1437,37 +1428,10 @@
      * state: {@link #onStartInput} if input is active, and
      * {@link #onCreateInputView} and {@link #onStartInputView} and related
      * appropriate functions if the UI is displayed.
-     * <p>Starting with {@link Build.VERSION_CODES#S}, IMEs can opt into handling configuration
-     * changes themselves instead of being restarted with
-     * {@link android.R.styleable#InputMethod_configChanges}.
      */
     @Override public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        if (shouldImeRestartForConfig(newConfig)) {
-            resetStateForNewConfiguration();
-        }
-    }
-
-    /**
-     * @return {@code true} if {@link InputMethodService} needs to restart to handle
-     * .{@link #onConfigurationChanged(Configuration)}
-     */
-    @VisibleForTesting
-    boolean shouldImeRestartForConfig(@NonNull Configuration newConfig) {
-        if (mLastKnownConfig == null) {
-            return true;
-        }
-        // If the new config is the same as the config this Service is already running with,
-        // then don't bother calling resetStateForNewConfiguration.
-        int diff = mLastKnownConfig.diffPublicOnly(newConfig);
-        if (diff != 0) {
-            // remove attrs not-relevant to IME service.
-            diff &= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
-            diff &= ActivityInfo.CONFIG_KEYBOARD;
-            diff &= ActivityInfo.CONFIG_NAVIGATION;
-        }
-        int unhandledDiff = (diff & ~mHandledConfigChanges);
-        return unhandledDiff != 0;
+        resetStateForNewConfiguration();
     }
 
     private void resetStateForNewConfiguration() {
@@ -3217,17 +3181,7 @@
             requestHideSelf(InputMethodManager.HIDE_NOT_ALWAYS);
         }
     }
-
-    @VisibleForTesting
-    void setLastKnownConfig(@NonNull Configuration config) {
-        mLastKnownConfig = config;
-    }
-
-    @VisibleForTesting
-    void setHandledConfigChanges(int configChanges) {
-        mHandledConfigChanges = configChanges;
-    }
-
+    
     void startExtractingText(boolean inputChanged) {
         final ExtractEditText eet = mExtractEditText;
         if (eet != null && getCurrentInputStarted()
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index 0baf11e..dc3b88a 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -19,7 +19,7 @@
 import android.net.DataUsageRequest;
 import android.net.INetworkStatsSession;
 import android.net.Network;
-import android.net.NetworkState;
+import android.net.NetworkStateSnapshot;
 import android.net.NetworkStats;
 import android.net.NetworkStatsHistory;
 import android.net.NetworkTemplate;
@@ -68,7 +68,7 @@
     /** Force update of ifaces. */
     void forceUpdateIfaces(
          in Network[] defaultNetworks,
-         in NetworkState[] networkStates,
+         in NetworkStateSnapshot[] snapshots,
          in String activeIface,
          in UnderlyingNetworkInfo[] underlyingNetworkInfos);
     /** Force update of statistics. */
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
index 183f500..cc1312b 100644
--- a/core/java/android/net/Ikev2VpnProfile.java
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -24,10 +24,7 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresFeature;
 import android.content.pm.PackageManager;
-import android.os.Process;
 import android.security.Credentials;
-import android.security.KeyStore;
-import android.security.keystore.AndroidKeyStoreProvider;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.net.VpnProfile;
@@ -35,7 +32,9 @@
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.security.GeneralSecurityException;
+import java.security.Key;
 import java.security.KeyFactory;
+import java.security.KeyStore;
 import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
 import java.security.cert.CertificateEncodingException;
@@ -66,6 +65,7 @@
     /** Prefix for when a Private Key is stored directly in the profile @hide */
     public static final String PREFIX_INLINE = "INLINE:";
 
+    private static final String ANDROID_KEYSTORE_PROVIDER = "AndroidKeyStore";
     private static final String MISSING_PARAM_MSG_TMPL = "Required parameter was not provided: %s";
     private static final String EMPTY_CERT = "";
 
@@ -430,32 +430,31 @@
         return profile;
     }
 
-    /**
-     * Constructs a Ikev2VpnProfile from an internal-use VpnProfile instance.
-     *
-     * <p>Redundant authentication information (not related to profile type) will be discarded.
-     *
-     * @hide
-     */
-    @NonNull
-    public static Ikev2VpnProfile fromVpnProfile(@NonNull VpnProfile profile)
-            throws IOException, GeneralSecurityException {
-        return fromVpnProfile(profile, null);
+    private static PrivateKey getPrivateKeyFromAndroidKeystore(String alias) {
+        try {
+            final KeyStore keystore = KeyStore.getInstance(ANDROID_KEYSTORE_PROVIDER);
+            keystore.load(null);
+            final Key key = keystore.getKey(alias, null);
+            if (!(key instanceof PrivateKey)) {
+                throw new IllegalStateException(
+                        "Unexpected key type returned from android keystore.");
+            }
+            return (PrivateKey) key;
+        } catch (Exception e) {
+            throw new IllegalStateException("Failed to load key from android keystore.", e);
+        }
     }
 
     /**
      * Builds the Ikev2VpnProfile from the given profile.
      *
      * @param profile the source VpnProfile to build from
-     * @param keyStore the Android Keystore instance to use to retrieve the private key, or null if
-     *     the private key is PEM-encoded into the profile.
      * @return The IKEv2/IPsec VPN profile
      * @hide
      */
     @NonNull
-    public static Ikev2VpnProfile fromVpnProfile(
-            @NonNull VpnProfile profile, @Nullable KeyStore keyStore)
-            throws IOException, GeneralSecurityException {
+    public static Ikev2VpnProfile fromVpnProfile(@NonNull VpnProfile profile)
+            throws GeneralSecurityException {
         final Builder builder = new Builder(profile.server, profile.ipsecIdentifier);
         builder.setProxy(profile.proxy);
         builder.setAllowedAlgorithms(profile.getAllowedAlgorithms());
@@ -479,12 +478,9 @@
             case TYPE_IKEV2_IPSEC_RSA:
                 final PrivateKey key;
                 if (profile.ipsecSecret.startsWith(PREFIX_KEYSTORE_ALIAS)) {
-                    Objects.requireNonNull(keyStore, "Missing Keystore for aliased PrivateKey");
-
                     final String alias =
                             profile.ipsecSecret.substring(PREFIX_KEYSTORE_ALIAS.length());
-                    key = AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore(
-                            keyStore, alias, Process.myUid());
+                    key = getPrivateKeyFromAndroidKeystore(alias);
                 } else if (profile.ipsecSecret.startsWith(PREFIX_INLINE)) {
                     key = getPrivateKey(profile.ipsecSecret.substring(PREFIX_INLINE.length()));
                 } else {
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
index e89451e..268002f 100644
--- a/core/java/android/net/IpSecAlgorithm.java
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -146,6 +146,25 @@
     public static final String AUTH_AES_XCBC = "xcbc(aes)";
 
     /**
+     * AES-CMAC Authentication/Integrity Algorithm.
+     *
+     * <p>Keys for this algorithm must be 128 bits in length.
+     *
+     * <p>The only valid truncation length is 96 bits.
+     *
+     * <p>This algorithm may be available on the device. Caller MUST check if it is supported before
+     * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is
+     * included in the returned algorithm set. The returned algorithm set will not change unless the
+     * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is
+     * requested on an unsupported device.
+     *
+     * <p>@see {@link #getSupportedAlgorithms()}
+     */
+    // This algorithm may be available on devices released before Android 12, and is guaranteed
+    // to be available on devices first shipped with Android 12 or later.
+    public static final String AUTH_AES_CMAC = "cmac(aes)";
+
+    /**
      * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm.
      *
      * <p>Valid lengths for keying material are {160, 224, 288}.
@@ -191,6 +210,7 @@
         AUTH_HMAC_SHA384,
         AUTH_HMAC_SHA512,
         AUTH_AES_XCBC,
+        AUTH_AES_CMAC,
         AUTH_CRYPT_AES_GCM,
         AUTH_CRYPT_CHACHA20_POLY1305
     })
@@ -212,10 +232,10 @@
         ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA512, SDK_VERSION_ZERO);
         ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_AES_GCM, SDK_VERSION_ZERO);
 
-        // STOPSHIP: b/170424293 Use Build.VERSION_CODES.S when it is defined
-        ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.R + 1);
-        ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.R + 1);
-        ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.R + 1);
+        ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.S);
+        ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.S);
+        ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_CMAC, Build.VERSION_CODES.S);
+        ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.S);
     }
 
     private static final Set<String> ENABLED_ALGOS =
@@ -383,6 +403,10 @@
                 isValidLen = keyLen == 128;
                 isValidTruncLen = truncLen == 96;
                 break;
+            case AUTH_AES_CMAC:
+                isValidLen = keyLen == 128;
+                isValidTruncLen = truncLen == 96;
+                break;
             case AUTH_CRYPT_AES_GCM:
                 // The keying material for GCM is a key plus a 32-bit salt
                 isValidLen = keyLen == 128 + 32 || keyLen == 192 + 32 || keyLen == 256 + 32;
@@ -416,6 +440,7 @@
             case AUTH_HMAC_SHA384:
             case AUTH_HMAC_SHA512:
             case AUTH_AES_XCBC:
+            case AUTH_AES_CMAC:
                 return true;
             default:
                 return false;
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index 32b19a4..a5ece7b 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -41,6 +41,22 @@
 
     public static final int SUBTYPE_COMBINED = -1;
 
+    /**
+     * Network has no {@code NetworkCapabilities#NET_CAPABILITY_OEM_*}.
+     * @hide
+     */
+    public static final int OEM_NONE = 0x0;
+    /**
+     * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID}.
+     * @hide
+     */
+    public static final int OEM_PAID = 0x1;
+    /**
+     * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PRIVATE}.
+     * @hide
+     */
+    public static final int OEM_PRIVATE = 0x2;
+
     final int mType;
     final int mSubType;
     final String mSubscriberId;
@@ -48,10 +64,11 @@
     final boolean mRoaming;
     final boolean mMetered;
     final boolean mDefaultNetwork;
+    final int mOemManaged;
 
     public NetworkIdentity(
             int type, int subType, String subscriberId, String networkId, boolean roaming,
-            boolean metered, boolean defaultNetwork) {
+            boolean metered, boolean defaultNetwork, int oemManaged) {
         mType = type;
         mSubType = subType;
         mSubscriberId = subscriberId;
@@ -59,12 +76,13 @@
         mRoaming = roaming;
         mMetered = metered;
         mDefaultNetwork = defaultNetwork;
+        mOemManaged = oemManaged;
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(mType, mSubType, mSubscriberId, mNetworkId, mRoaming, mMetered,
-                mDefaultNetwork);
+                mDefaultNetwork, mOemManaged);
     }
 
     @Override
@@ -75,7 +93,8 @@
                     && Objects.equals(mSubscriberId, ident.mSubscriberId)
                     && Objects.equals(mNetworkId, ident.mNetworkId)
                     && mMetered == ident.mMetered
-                    && mDefaultNetwork == ident.mDefaultNetwork;
+                    && mDefaultNetwork == ident.mDefaultNetwork
+                    && mOemManaged == ident.mOemManaged;
         }
         return false;
     }
@@ -102,6 +121,8 @@
         }
         builder.append(", metered=").append(mMetered);
         builder.append(", defaultNetwork=").append(mDefaultNetwork);
+        // TODO(180557699): Print a human readable string for OEM managed state.
+        builder.append(", oemManaged=").append(mOemManaged);
         return builder.append("}").toString();
     }
 
@@ -120,6 +141,7 @@
         proto.write(NetworkIdentityProto.ROAMING, mRoaming);
         proto.write(NetworkIdentityProto.METERED, mMetered);
         proto.write(NetworkIdentityProto.DEFAULT_NETWORK, mDefaultNetwork);
+        proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK, mOemManaged);
 
         proto.end(start);
     }
@@ -152,28 +174,47 @@
         return mDefaultNetwork;
     }
 
-    /**
-     * Build a {@link NetworkIdentity} from the given {@link NetworkState} and {@code subType},
-     * assuming that any mobile networks are using the current IMSI. The subType if applicable,
-     * should be set as one of the TelephonyManager.NETWORK_TYPE_* constants, or
-     * {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not.
-     */
-    public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state,
-            boolean defaultNetwork, @NetworkType int subType) {
-        final int legacyType = state.legacyNetworkType;
+    public int getOemManaged() {
+        return mOemManaged;
+    }
 
-        String subscriberId = null;
+    /**
+     * Build a {@link NetworkIdentity} from the given {@link NetworkState} and
+     * {@code subType}, assuming that any mobile networks are using the current IMSI.
+     * The subType if applicable, should be set as one of the TelephonyManager.NETWORK_TYPE_*
+     * constants, or {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not.
+     */
+    // TODO: Delete this function after NetworkPolicyManagerService finishes the migration.
+    public static NetworkIdentity buildNetworkIdentity(Context context,
+            NetworkState state, boolean defaultNetwork, @NetworkType int subType) {
+        final NetworkStateSnapshot snapshot = new NetworkStateSnapshot(state.network,
+                state.networkCapabilities, state.linkProperties, state.subscriberId,
+                state.legacyNetworkType);
+        return buildNetworkIdentity(context, snapshot, defaultNetwork, subType);
+    }
+
+    /**
+     * Build a {@link NetworkIdentity} from the given {@link NetworkStateSnapshot} and
+     * {@code subType}, assuming that any mobile networks are using the current IMSI.
+     * The subType if applicable, should be set as one of the TelephonyManager.NETWORK_TYPE_*
+     * constants, or {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not.
+     */
+    public static NetworkIdentity buildNetworkIdentity(Context context,
+            NetworkStateSnapshot snapshot, boolean defaultNetwork, @NetworkType int subType) {
+        final int legacyType = snapshot.legacyType;
+
+        final String subscriberId = snapshot.subscriberId;
         String networkId = null;
-        boolean roaming = !state.networkCapabilities.hasCapability(
+        boolean roaming = !snapshot.networkCapabilities.hasCapability(
                 NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
-        boolean metered = !state.networkCapabilities.hasCapability(
+        boolean metered = !snapshot.networkCapabilities.hasCapability(
                 NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
 
-        subscriberId = state.subscriberId;
+        final int oemManaged = getOemBitfield(snapshot.networkCapabilities);
 
         if (legacyType == TYPE_WIFI) {
-            if (state.networkCapabilities.getSsid() != null) {
-                networkId = state.networkCapabilities.getSsid();
+            if (snapshot.networkCapabilities.getSsid() != null) {
+                networkId = snapshot.networkCapabilities.getSsid();
                 if (networkId == null) {
                     // TODO: Figure out if this code path never runs. If so, remove them.
                     final WifiManager wifi = (WifiManager) context.getSystemService(
@@ -185,7 +226,24 @@
         }
 
         return new NetworkIdentity(legacyType, subType, subscriberId, networkId, roaming, metered,
-                defaultNetwork);
+                defaultNetwork, oemManaged);
+    }
+
+    /**
+     * Builds a bitfield of {@code NetworkIdentity.OEM_*} based on {@link NetworkCapabilities}.
+     * @hide
+     */
+    public static int getOemBitfield(NetworkCapabilities nc) {
+        int oemManaged = OEM_NONE;
+
+        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID)) {
+            oemManaged |= OEM_PAID;
+        }
+        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE)) {
+            oemManaged |= OEM_PRIVATE;
+        }
+
+        return oemManaged;
     }
 
     @Override
@@ -209,6 +267,9 @@
         if (res == 0) {
             res = Boolean.compare(mDefaultNetwork, another.mDefaultNetwork);
         }
+        if (res == 0) {
+            res = Integer.compare(mOemManaged, another.mOemManaged);
+        }
         return res;
     }
 }
diff --git a/core/java/android/net/NetworkStateSnapshot.aidl b/core/java/android/net/NetworkStateSnapshot.aidl
new file mode 100644
index 0000000..cb602d79
--- /dev/null
+++ b/core/java/android/net/NetworkStateSnapshot.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.net;
+
+parcelable NetworkStateSnapshot;
diff --git a/core/java/android/net/NetworkStateSnapshot.java b/core/java/android/net/NetworkStateSnapshot.java
new file mode 100644
index 0000000..b3d8d4e
--- /dev/null
+++ b/core/java/android/net/NetworkStateSnapshot.java
@@ -0,0 +1,127 @@
+/*
+ * 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.net;
+
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Snapshot of network state.
+ *
+ * @hide
+ */
+@SystemApi(client = MODULE_LIBRARIES)
+public final class NetworkStateSnapshot implements Parcelable {
+    /** The network associated with this snapshot. */
+    @NonNull
+    public final Network network;
+
+    /** The {@link NetworkCapabilities} of the network associated with this snapshot. */
+    @NonNull
+    public final NetworkCapabilities networkCapabilities;
+
+    /** The {@link LinkProperties} of the network associated with this snapshot. */
+    @NonNull
+    public final LinkProperties linkProperties;
+
+    /**
+     * The Subscriber Id of the network associated with this snapshot. See
+     * {@link android.telephony.TelephonyManager#getSubscriberId()}.
+     */
+    @Nullable
+    public final String subscriberId;
+
+    /**
+     * The legacy type of the network associated with this snapshot. See
+     * {@code ConnectivityManager#TYPE_*}.
+     */
+    public final int legacyType;
+
+    public NetworkStateSnapshot(@NonNull Network network,
+            @NonNull NetworkCapabilities networkCapabilities,
+            @NonNull LinkProperties linkProperties,
+            @Nullable String subscriberId, int legacyType) {
+        this.network = Objects.requireNonNull(network);
+        this.networkCapabilities = Objects.requireNonNull(networkCapabilities);
+        this.linkProperties = Objects.requireNonNull(linkProperties);
+        this.subscriberId = subscriberId;
+        this.legacyType = legacyType;
+    }
+
+    /** @hide */
+    public NetworkStateSnapshot(@NonNull Parcel in) {
+        network = in.readParcelable(null);
+        networkCapabilities = in.readParcelable(null);
+        linkProperties = in.readParcelable(null);
+        subscriberId = in.readString();
+        legacyType = in.readInt();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeParcelable(network, flags);
+        out.writeParcelable(networkCapabilities, flags);
+        out.writeParcelable(linkProperties, flags);
+        out.writeString(subscriberId);
+        out.writeInt(legacyType);
+    }
+
+    @NonNull
+    public static final Creator<NetworkStateSnapshot> CREATOR =
+            new Creator<NetworkStateSnapshot>() {
+        @NonNull
+        @Override
+        public NetworkStateSnapshot createFromParcel(@NonNull Parcel in) {
+            return new NetworkStateSnapshot(in);
+        }
+
+        @NonNull
+        @Override
+        public NetworkStateSnapshot[] newArray(int size) {
+            return new NetworkStateSnapshot[size];
+        }
+    };
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof NetworkStateSnapshot)) return false;
+        NetworkStateSnapshot that = (NetworkStateSnapshot) o;
+        return legacyType == that.legacyType
+                && Objects.equals(network, that.network)
+                && Objects.equals(networkCapabilities, that.networkCapabilities)
+                && Objects.equals(linkProperties, that.linkProperties)
+                && Objects.equals(subscriberId, that.subscriberId);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(network, networkCapabilities, linkProperties, subscriberId, legacyType);
+    }
+}
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index aa61e03..c83dd99 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -23,6 +23,7 @@
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
 import static android.net.ConnectivityManager.TYPE_WIMAX;
+import static android.net.NetworkIdentity.OEM_NONE;
 import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
 import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
 import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
@@ -99,6 +100,22 @@
      */
     public static final int NETWORK_TYPE_5G_NSA = -2;
 
+    /**
+     * Value to match both OEM managed and unmanaged networks (all networks).
+     * @hide
+     */
+    public static final int OEM_MANAGED_ALL = -1;
+    /**
+     * Value to match networks which are not OEM managed.
+     * @hide
+     */
+    public static final int OEM_MANAGED_NO = OEM_NONE;
+    /**
+     * Value to match any OEM managed network.
+     * @hide
+     */
+    public static final int OEM_MANAGED_YES = -2;
+
     private static boolean isKnownMatchRule(final int rule) {
         switch (rule) {
             case MATCH_MOBILE:
@@ -151,10 +168,10 @@
             @NetworkType int ratType) {
         if (TextUtils.isEmpty(subscriberId)) {
             return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null,
-                    METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType);
+                    METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL);
         }
         return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null,
-                METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType);
+                METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL);
     }
 
     /**
@@ -235,6 +252,9 @@
     private final int mDefaultNetwork;
     private final int mSubType;
 
+    // Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}.
+    private final int mOemManaged;
+
     @UnsupportedAppUsage
     public NetworkTemplate(int matchRule, String subscriberId, String networkId) {
         this(matchRule, subscriberId, new String[] { subscriberId }, networkId);
@@ -243,11 +263,12 @@
     public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
             String networkId) {
         this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL,
-                DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL);
+                DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL);
     }
 
     public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
-            String networkId, int metered, int roaming, int defaultNetwork, int subType) {
+            String networkId, int metered, int roaming, int defaultNetwork, int subType,
+            int oemManaged) {
         mMatchRule = matchRule;
         mSubscriberId = subscriberId;
         mMatchSubscriberIds = matchSubscriberIds;
@@ -256,6 +277,7 @@
         mRoaming = roaming;
         mDefaultNetwork = defaultNetwork;
         mSubType = subType;
+        mOemManaged = oemManaged;
 
         if (!isKnownMatchRule(matchRule)) {
             Log.e(TAG, "Unknown network template rule " + matchRule
@@ -272,6 +294,7 @@
         mRoaming = in.readInt();
         mDefaultNetwork = in.readInt();
         mSubType = in.readInt();
+        mOemManaged = in.readInt();
     }
 
     @Override
@@ -284,6 +307,7 @@
         dest.writeInt(mRoaming);
         dest.writeInt(mDefaultNetwork);
         dest.writeInt(mSubType);
+        dest.writeInt(mOemManaged);
     }
 
     @Override
@@ -319,13 +343,16 @@
         if (mSubType != NETWORK_TYPE_ALL) {
             builder.append(", subType=").append(mSubType);
         }
+        if (mOemManaged != OEM_MANAGED_ALL) {
+            builder.append(", oemManaged=").append(mOemManaged);
+        }
         return builder.toString();
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming,
-                mDefaultNetwork, mSubType);
+                mDefaultNetwork, mSubType, mOemManaged);
     }
 
     @Override
@@ -338,7 +365,8 @@
                     && mMetered == other.mMetered
                     && mRoaming == other.mRoaming
                     && mDefaultNetwork == other.mDefaultNetwork
-                    && mSubType == other.mSubType;
+                    && mSubType == other.mSubType
+                    && mOemManaged == other.mOemManaged;
         }
         return false;
     }
@@ -384,6 +412,7 @@
         if (!matchesMetered(ident)) return false;
         if (!matchesRoaming(ident)) return false;
         if (!matchesDefaultNetwork(ident)) return false;
+        if (!matchesOemNetwork(ident)) return false;
 
         switch (mMatchRule) {
             case MATCH_MOBILE:
@@ -425,6 +454,13 @@
             || (mDefaultNetwork == DEFAULT_NETWORK_NO && !ident.mDefaultNetwork);
     }
 
+    private boolean matchesOemNetwork(NetworkIdentity ident) {
+        return (mOemManaged == OEM_MANAGED_ALL)
+            || (mOemManaged == OEM_MANAGED_YES
+                    && ident.mOemManaged != OEM_NONE)
+            || (mOemManaged == ident.mOemManaged);
+    }
+
     private boolean matchesCollapsedRatType(NetworkIdentity ident) {
         return mSubType == NETWORK_TYPE_ALL
                 || getCollapsedRatType(mSubType) == getCollapsedRatType(ident.mSubType);
diff --git a/core/java/android/net/OemNetworkPreferences.java b/core/java/android/net/OemNetworkPreferences.java
index b403455..48bd297 100644
--- a/core/java/android/net/OemNetworkPreferences.java
+++ b/core/java/android/net/OemNetworkPreferences.java
@@ -29,7 +29,15 @@
 import java.util.Map;
 import java.util.Objects;
 
-/** @hide */
+/**
+ * Network preferences to set the default active network on a per-application basis as per a given
+ * {@link OemNetworkPreference}. An example of this would be to set an application's network
+ * preference to {@link #OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK} which would have the default
+ * network for that application set to an unmetered network first if available and if not, it then
+ * set that application's default network to an OEM managed network if available.
+ *
+ * @hide
+ */
 @SystemApi
 public final class OemNetworkPreferences implements Parcelable {
     /**
@@ -64,6 +72,10 @@
     @NonNull
     private final Bundle mNetworkMappings;
 
+    /**
+     * Return the currently built application package name to {@link OemNetworkPreference} mappings.
+     * @return the current network preferences map.
+     */
     @NonNull
     public Map<String, Integer> getNetworkPreferences() {
         return convertToUnmodifiableMap(mNetworkMappings);
@@ -105,6 +117,11 @@
             mNetworkMappings = new Bundle();
         }
 
+        /**
+         * Constructor to populate the builder's values with an already built
+         * {@link OemNetworkPreferences}.
+         * @param preferences the {@link OemNetworkPreferences} to populate with.
+         */
         public Builder(@NonNull final OemNetworkPreferences preferences) {
             Objects.requireNonNull(preferences);
             mNetworkMappings = (Bundle) preferences.mNetworkMappings.clone();
diff --git a/packages/Connectivity/framework/src/android/net/PacProxySelector.java b/core/java/android/net/PacProxySelector.java
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/PacProxySelector.java
rename to core/java/android/net/PacProxySelector.java
diff --git a/packages/Connectivity/framework/src/android/net/Proxy.java b/core/java/android/net/Proxy.java
similarity index 100%
rename from packages/Connectivity/framework/src/android/net/Proxy.java
rename to core/java/android/net/Proxy.java
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index f90fbaf..fa3ff8a 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -41,6 +41,7 @@
 import android.os.ServiceManager;
 import android.os.UserHandle;
 
+import com.android.internal.net.NetworkUtilsInternal;
 import com.android.internal.net.VpnConfig;
 
 import java.net.DatagramSocket;
@@ -254,7 +255,7 @@
      * @return {@code true} on success.
      */
     public boolean protect(int socket) {
-        return NetworkUtils.protectFromVpn(socket);
+        return NetworkUtilsInternal.protectFromVpn(socket);
     }
 
     /**
diff --git a/packages/Connectivity/framework/src/android/net/util/SocketUtils.java b/core/java/android/net/util/SocketUtils.java
similarity index 97%
rename from packages/Connectivity/framework/src/android/net/util/SocketUtils.java
rename to core/java/android/net/util/SocketUtils.java
index e64060f..69edc75 100644
--- a/packages/Connectivity/framework/src/android/net/util/SocketUtils.java
+++ b/core/java/android/net/util/SocketUtils.java
@@ -22,12 +22,13 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.net.NetworkUtils;
 import android.system.ErrnoException;
 import android.system.NetlinkSocketAddress;
 import android.system.Os;
 import android.system.PacketSocketAddress;
 
+import com.android.internal.net.NetworkUtilsInternal;
+
 import libcore.io.IoBridge;
 
 import java.io.FileDescriptor;
@@ -51,7 +52,7 @@
         // of struct ifreq is a NULL-terminated interface name.
         // TODO: add a setsockoptString()
         Os.setsockoptIfreq(socket, SOL_SOCKET, SO_BINDTODEVICE, iface);
-        NetworkUtils.protectFromVpn(socket);
+        NetworkUtilsInternal.protectFromVpn(socket);
     }
 
     /**
diff --git a/core/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtils.java b/core/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtils.java
new file mode 100644
index 0000000..6bbc6b1
--- /dev/null
+++ b/core/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtils.java
@@ -0,0 +1,74 @@
+/*
+ * 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.net.vcn.persistablebundleutils;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import android.annotation.NonNull;
+import android.net.InetAddresses;
+import android.net.ipsec.ike.IkeTrafficSelector;
+import android.os.PersistableBundle;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Objects;
+
+/**
+ * Provides utility methods to convert IkeTrafficSelector to/from PersistableBundle.
+ *
+ * @hide
+ */
+@VisibleForTesting(visibility = Visibility.PRIVATE)
+public final class IkeTrafficSelectorUtils {
+    private static final String START_PORT_KEY = "START_PORT_KEY";
+    private static final String END_PORT_KEY = "END_PORT_KEY";
+    private static final String START_ADDRESS_KEY = "START_ADDRESS_KEY";
+    private static final String END_ADDRESS_KEY = "END_ADDRESS_KEY";
+
+    /** Constructs an IkeTrafficSelector by deserializing a PersistableBundle. */
+    @NonNull
+    public static IkeTrafficSelector fromPersistableBundle(@NonNull PersistableBundle in) {
+        Objects.requireNonNull(in, "PersistableBundle was null");
+
+        final int startPort = in.getInt(START_PORT_KEY);
+        final int endPort = in.getInt(END_PORT_KEY);
+
+        final String startingAddress = in.getString(START_ADDRESS_KEY);
+        final String endingAddress = in.getString(END_ADDRESS_KEY);
+        Objects.requireNonNull(startingAddress, "startAddress was null");
+        Objects.requireNonNull(startingAddress, "endAddress was null");
+
+        return new IkeTrafficSelector(
+                startPort,
+                endPort,
+                InetAddresses.parseNumericAddress(startingAddress),
+                InetAddresses.parseNumericAddress(endingAddress));
+    }
+
+    /** Serializes an IkeTrafficSelector to a PersistableBundle. */
+    @NonNull
+    public static PersistableBundle toPersistableBundle(@NonNull IkeTrafficSelector ts) {
+        final PersistableBundle result = new PersistableBundle();
+
+        result.putInt(START_PORT_KEY, ts.startPort);
+        result.putInt(END_PORT_KEY, ts.endPort);
+        result.putString(START_ADDRESS_KEY, ts.startingAddress.getHostAddress());
+        result.putString(END_ADDRESS_KEY, ts.endingAddress.getHostAddress());
+
+        return result;
+    }
+}
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java
index c6efaac..2b6f336 100644
--- a/core/java/android/os/BatteryConsumer.java
+++ b/core/java/android/os/BatteryConsumer.java
@@ -47,6 +47,7 @@
             POWER_COMPONENT_SYSTEM_SERVICES,
             POWER_COMPONENT_SENSORS,
             POWER_COMPONENT_GNSS,
+            POWER_COMPONENT_WIFI,
             POWER_COMPONENT_WAKELOCK,
             POWER_COMPONENT_SCREEN,
             POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS,
@@ -66,6 +67,7 @@
     public static final int POWER_COMPONENT_MOBILE_RADIO = 8;
     public static final int POWER_COMPONENT_SENSORS = 9;
     public static final int POWER_COMPONENT_GNSS = 10;
+    public static final int POWER_COMPONENT_WIFI = 11;
     public static final int POWER_COMPONENT_WAKELOCK = 12;
     public static final int POWER_COMPONENT_SCREEN = 13;
     // Power that is re-attributed to other battery consumers. For example, for System Server
@@ -94,6 +96,7 @@
             TIME_COMPONENT_MOBILE_RADIO,
             TIME_COMPONENT_SENSORS,
             TIME_COMPONENT_GNSS,
+            TIME_COMPONENT_WIFI,
             TIME_COMPONENT_WAKELOCK,
             TIME_COMPONENT_SCREEN,
     })
@@ -112,6 +115,7 @@
     public static final int TIME_COMPONENT_MOBILE_RADIO = 8;
     public static final int TIME_COMPONENT_SENSORS = 9;
     public static final int TIME_COMPONENT_GNSS = 10;
+    public static final int TIME_COMPONENT_WIFI = 11;
     public static final int TIME_COMPONENT_WAKELOCK = 12;
     public static final int TIME_COMPONENT_SCREEN = 13;
 
diff --git a/core/java/android/os/BatterySaverPolicyConfig.java b/core/java/android/os/BatterySaverPolicyConfig.java
index 81c781b..a999e65 100644
--- a/core/java/android/os/BatterySaverPolicyConfig.java
+++ b/core/java/android/os/BatterySaverPolicyConfig.java
@@ -247,6 +247,7 @@
     /**
      * Get the SoundTrigger mode while in Battery Saver.
      */
+    @PowerManager.SoundTriggerPowerSaveMode
     public int getSoundTriggerMode() {
         return mSoundTriggerMode;
     }
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index cf9b534..6901df7 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2179,12 +2179,6 @@
 
     public abstract void finishIteratingHistoryLocked();
 
-    public abstract boolean startIteratingOldHistoryLocked();
-
-    public abstract boolean getNextOldHistoryLocked(HistoryItem out);
-
-    public abstract void finishIteratingOldHistoryLocked();
-
     /**
      * Return the base time offset for the battery history.
      */
@@ -7061,24 +7055,6 @@
                     finishIteratingHistoryLocked();
                 }
             }
-
-            if (startIteratingOldHistoryLocked()) {
-                try {
-                    final HistoryItem rec = new HistoryItem();
-                    pw.println("Old battery History:");
-                    HistoryPrinter hprinter = new HistoryPrinter();
-                    long baseTime = -1;
-                    while (getNextOldHistoryLocked(rec)) {
-                        if (baseTime < 0) {
-                            baseTime = rec.time;
-                        }
-                        hprinter.printNextItem(pw, rec, baseTime, false, (flags&DUMP_VERBOSE) != 0);
-                    }
-                    pw.println();
-                } finally {
-                    finishIteratingOldHistoryLocked();
-                }
-            }
         }
 
         if (filtering && (flags&(DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) == 0) {
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index 35a5a7c..de7b885 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -20,6 +20,9 @@
 import android.util.Range;
 import android.util.SparseArray;
 
+import com.android.internal.os.BatteryStatsHistory;
+import com.android.internal.os.BatteryStatsHistoryIterator;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -37,12 +40,16 @@
     private final ArrayList<UidBatteryConsumer> mUidBatteryConsumers;
     private final ArrayList<SystemBatteryConsumer> mSystemBatteryConsumers;
     private final ArrayList<UserBatteryConsumer> mUserBatteryConsumers;
+    private final Parcel mHistoryBuffer;
+    private final List<BatteryStats.HistoryTag> mHistoryTagPool;
 
     private BatteryUsageStats(@NonNull Builder builder) {
         mStatsStartRealtimeMs = builder.mStatsStartRealtimeMs;
         mDischargePercentage = builder.mDischargePercentage;
         mDischargedPowerLowerBound = builder.mDischargedPowerLowerBoundMah;
         mDischargedPowerUpperBound = builder.mDischargedPowerUpperBoundMah;
+        mHistoryBuffer = builder.mHistoryBuffer;
+        mHistoryTagPool = builder.mHistoryTagPool;
 
         double totalPower = 0;
 
@@ -125,6 +132,19 @@
         return mUserBatteryConsumers;
     }
 
+    /**
+     * Returns an iterator for {@link android.os.BatteryStats.HistoryItem}'s.
+     */
+    @NonNull
+    public BatteryStatsHistoryIterator iterateBatteryStatsHistory() {
+        if (mHistoryBuffer == null) {
+            throw new IllegalStateException(
+                    "Battery history was not requested in the BatteryUsageStatsQuery");
+        }
+        return new BatteryStatsHistoryIterator(new BatteryStatsHistory(mHistoryBuffer),
+                mHistoryTagPool);
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -142,6 +162,29 @@
         source.readParcelableList(mSystemBatteryConsumers, getClass().getClassLoader());
         mUserBatteryConsumers = new ArrayList<>();
         source.readParcelableList(mUserBatteryConsumers, getClass().getClassLoader());
+        if (source.readBoolean()) {
+            mHistoryBuffer = Parcel.obtain();
+            mHistoryBuffer.setDataSize(0);
+            mHistoryBuffer.setDataPosition(0);
+
+            int historyBufferSize = source.readInt();
+            int curPos = source.dataPosition();
+            mHistoryBuffer.appendFrom(source, curPos, historyBufferSize);
+            source.setDataPosition(curPos + historyBufferSize);
+
+            int historyTagCount = source.readInt();
+            mHistoryTagPool = new ArrayList<>(historyTagCount);
+            for (int i = 0; i < historyTagCount; i++) {
+                BatteryStats.HistoryTag tag = new BatteryStats.HistoryTag();
+                tag.string = source.readString();
+                tag.uid = source.readInt();
+                tag.poolIdx = source.readInt();
+                mHistoryTagPool.add(tag);
+            }
+        } else {
+            mHistoryBuffer = null;
+            mHistoryTagPool = null;
+        }
     }
 
     @Override
@@ -154,6 +197,23 @@
         dest.writeParcelableList(mUidBatteryConsumers, flags);
         dest.writeParcelableList(mSystemBatteryConsumers, flags);
         dest.writeParcelableList(mUserBatteryConsumers, flags);
+        if (mHistoryBuffer != null) {
+            dest.writeBoolean(true);
+
+            final int historyBufferSize = mHistoryBuffer.dataSize();
+            dest.writeInt(historyBufferSize);
+            dest.appendFrom(mHistoryBuffer, 0, historyBufferSize);
+
+            dest.writeInt(mHistoryTagPool.size());
+            for (int i = mHistoryTagPool.size() - 1; i >= 0; i--) {
+                final BatteryStats.HistoryTag tag = mHistoryTagPool.get(i);
+                dest.writeString(tag.string);
+                dest.writeInt(tag.uid);
+                dest.writeInt(tag.poolIdx);
+            }
+        } else {
+            dest.writeBoolean(false);
+        }
     }
 
     @NonNull
@@ -183,6 +243,8 @@
                 new SparseArray<>();
         private final SparseArray<UserBatteryConsumer.Builder> mUserBatteryConsumerBuilders =
                 new SparseArray<>();
+        private Parcel mHistoryBuffer;
+        private List<BatteryStats.HistoryTag> mHistoryTagPool;
 
         public Builder(int customPowerComponentCount, int customTimeComponentCount) {
             mCustomPowerComponentCount = customPowerComponentCount;
@@ -227,6 +289,17 @@
         }
 
         /**
+         * Sets the parceled recent history.
+         */
+        @NonNull
+        public Builder setBatteryHistory(Parcel historyBuffer,
+                List<BatteryStats.HistoryTag> historyTagPool) {
+            mHistoryBuffer = historyBuffer;
+            mHistoryTagPool = historyTagPool;
+            return this;
+        }
+
+        /**
          * Creates or returns a exiting UidBatteryConsumer, which represents battery attribution
          * data for an individual UID.
          */
diff --git a/core/java/android/os/BatteryUsageStatsQuery.java b/core/java/android/os/BatteryUsageStatsQuery.java
index 17cb735..9518bf1 100644
--- a/core/java/android/os/BatteryUsageStatsQuery.java
+++ b/core/java/android/os/BatteryUsageStatsQuery.java
@@ -40,6 +40,7 @@
      */
     @IntDef(flag = true, prefix = { "FLAG_BATTERY_USAGE_STATS_" }, value = {
             FLAG_BATTERY_USAGE_STATS_POWER_PROFILE_MODEL,
+            FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface BatteryUsageStatsFlags {}
@@ -53,6 +54,12 @@
      */
     public static final int FLAG_BATTERY_USAGE_STATS_POWER_PROFILE_MODEL = 1;
 
+    /**
+     * Indicates that battery history should be included in the BatteryUsageStats.
+     * @hide
+     */
+    public static final int FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY = 2;
+
     private final int mFlags;
     @NonNull
     private final int[] mUserIds;
@@ -146,10 +153,10 @@
         }
 
         /**
-         * Sets flags to modify the behavior of {@link BatteryStatsManager#getBatteryUsageStats}.
+         * Requests that battery history be included in the BatteryUsageStats.
          */
-        public Builder setFlags(@BatteryUsageStatsFlags int flags) {
-            mFlags = flags;
+        public Builder includeBatteryHistory() {
+            mFlags |= BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY;
             return this;
         }
 
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index a435ac1..73bb8d5 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -68,8 +68,11 @@
     /**
      * An interface describing the callback for bugreport progress and status.
      *
-     * <p>In general, callers can expect to receive {@link #onProgress} calls as the bugreport
-     * progresses, followed by a terminal call to either {@link #onFinished} or {@link #onError}.
+     * <p>Callers will receive {@link #onProgress} calls as the bugreport progresses, followed by a
+     * terminal call to either {@link #onFinished} or {@link #onError}.
+     *
+     * <p>If an issue is encountered while starting the bugreport asynchronously, callers will
+     * receive an {@link #onError} call without any {@link #onProgress} callbacks.
      */
     public abstract static class BugreportCallback {
         /**
diff --git a/core/java/android/os/CombinedVibrationEffect.java b/core/java/android/os/CombinedVibrationEffect.java
index c8e682c..e068772 100644
--- a/core/java/android/os/CombinedVibrationEffect.java
+++ b/core/java/android/os/CombinedVibrationEffect.java
@@ -76,7 +76,9 @@
      * A sequential vibration effect should be performed by multiple vibrators in order.
      *
      * @see CombinedVibrationEffect.SequentialCombination
+     * @hide
      */
+    @TestApi
     @NonNull
     public static SequentialCombination startSequential() {
         return new SequentialCombination();
@@ -162,7 +164,9 @@
      * A combination of haptic effects that should be played in multiple vibrators in sequence.
      *
      * @see CombinedVibrationEffect#startSequential()
+     * @hide
      */
+    @TestApi
     public static final class SequentialCombination {
 
         private final ArrayList<CombinedVibrationEffect> mEffects = new ArrayList<>();
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 874add5..91d6a9b 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -23,7 +23,6 @@
 import android.net.Network;
 import android.net.NetworkStats;
 import android.net.RouteInfo;
-import android.net.UidRange;
 
 /**
  * @hide
@@ -182,11 +181,6 @@
     String[] listTetheredInterfaces();
 
     /**
-     * Sets the list of DNS forwarders (in order of priority)
-     */
-    void setDnsForwarders(in Network network, in String[] dns);
-
-    /**
      * Returns the list of DNS forwarders (in order of priority)
      */
     String[] getDnsForwarders();
@@ -300,8 +294,6 @@
     void setFirewallUidRules(int chain, in int[] uids, in int[] rules);
     void setFirewallChainEnabled(int chain, boolean enable);
 
-    void addLegacyRouteForNetId(int netId, in RouteInfo routeInfo, int uid);
-
     /**
      * Allow UID to call protect().
      */
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 7437e037..087568d 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -113,7 +113,7 @@
     boolean hasBadge(int userId);
     boolean isUserUnlocked(int userId);
     boolean isUserRunning(int userId);
-    boolean isUserForeground();
+    boolean isUserForeground(int userId);
     boolean isUserNameSet(int userId);
     boolean hasRestrictedProfiles();
     boolean requestQuietModeEnabled(String callingPackage, boolean enableQuietMode, int userId, in IntentSender target, int flags);
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index e29d756..d8f6344 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -338,8 +338,7 @@
                 try {
                     time = mMgr.getGnssTimeMillis();
                 } catch (RemoteException e) {
-                    e.rethrowFromSystemServer();
-                    return 0;
+                    throw e.rethrowFromSystemServer();
                 }
                 if (time == null) {
                     throw new DateTimeException("Gnss based time is not available.");
diff --git a/core/java/android/os/TEST_MAPPING b/core/java/android/os/TEST_MAPPING
index 1bdc82a..97e03e9 100644
--- a/core/java/android/os/TEST_MAPPING
+++ b/core/java/android/os/TEST_MAPPING
@@ -38,6 +38,23 @@
           "include-filter": "com.android.server.pm.parsing.PackageInfoUserFieldsTest"
         }
       ]
+    },
+    {
+      "file_patterns": ["BatteryStats.java"],
+      "name": "FrameworksCoreTests",
+      "options": [
+        { "include-filter": "com.android.internal.os.BatteryStatsTests" },
+        { "exclude-annotation": "com.android.internal.os.SkipPresubmit" }
+      ]
+    },
+    {
+      "file_patterns": ["BatteryStats.java"],
+      "name": "FrameworksServicesTests",
+      "options": [
+        { "include-filter": "com.android.server.am.BatteryStatsServiceTest" },
+        { "include-filter": "com.android.server.am.MeasuredEnergySnapshotTest" },
+        { "include-filter": "com.android.server.am.BatteryExternalStatsWorkerTest" }
+      ]
     }
   ],
   "postsubmit": [
diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java
index bb40d90..dfa0c39 100644
--- a/core/java/android/os/UidBatteryConsumer.java
+++ b/core/java/android/os/UidBatteryConsumer.java
@@ -16,9 +16,13 @@
 
 package android.os;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Contains power consumption data attributed to a specific UID.
  *
@@ -26,9 +30,37 @@
  */
 public final class UidBatteryConsumer extends BatteryConsumer implements Parcelable {
 
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            STATE_FOREGROUND,
+            STATE_BACKGROUND
+    })
+    public @interface State {
+    }
+
+    /**
+     * The state of an application when it is either running a foreground (top) activity
+     * or a foreground service.
+     */
+    public static final int STATE_FOREGROUND = 0;
+
+    /**
+     * The state of an application when it is running in the background, including the following
+     * states:
+     *
+     * {@link android.app.ActivityManager#PROCESS_STATE_IMPORTANT_BACKGROUND},
+     * {@link android.app.ActivityManager#PROCESS_STATE_TRANSIENT_BACKGROUND},
+     * {@link android.app.ActivityManager#PROCESS_STATE_BACKUP},
+     * {@link android.app.ActivityManager#PROCESS_STATE_SERVICE},
+     * {@link android.app.ActivityManager#PROCESS_STATE_RECEIVER}.
+     */
+    public static final int STATE_BACKGROUND = 1;
+
     private final int mUid;
     @Nullable
     private final String mPackageWithHighestDrain;
+    private final long mTimeInForegroundMs;
+    private final long mTimeInBackgroundMs;
 
     public int getUid() {
         return mUid;
@@ -39,16 +71,33 @@
         return mPackageWithHighestDrain;
     }
 
+    /**
+     * Returns the amount of time in milliseconds this UID spent in the specified state.
+     */
+    public long getTimeInStateMs(@State int state) {
+        switch (state) {
+            case STATE_BACKGROUND:
+                return mTimeInBackgroundMs;
+            case STATE_FOREGROUND:
+                return mTimeInForegroundMs;
+        }
+        return 0;
+    }
+
     private UidBatteryConsumer(@NonNull Builder builder) {
         super(builder.mPowerComponentsBuilder.build());
         mUid = builder.mUid;
         mPackageWithHighestDrain = builder.mPackageWithHighestDrain;
+        mTimeInForegroundMs = builder.mTimeInForegroundMs;
+        mTimeInBackgroundMs = builder.mTimeInBackgroundMs;
     }
 
     private UidBatteryConsumer(@NonNull Parcel source) {
         super(new PowerComponents(source));
         mUid = source.readInt();
         mPackageWithHighestDrain = source.readString();
+        mTimeInForegroundMs = source.readLong();
+        mTimeInBackgroundMs = source.readLong();
     }
 
     /**
@@ -59,6 +108,8 @@
         super.writeToParcel(dest, flags);
         dest.writeInt(mUid);
         dest.writeString(mPackageWithHighestDrain);
+        dest.writeLong(mTimeInForegroundMs);
+        dest.writeLong(mTimeInBackgroundMs);
     }
 
     @NonNull
@@ -84,6 +135,8 @@
         private final BatteryStats.Uid mBatteryStatsUid;
         private final int mUid;
         private String mPackageWithHighestDrain;
+        public long mTimeInForegroundMs;
+        public long mTimeInBackgroundMs;
         private boolean mExcludeFromBatteryUsageStats;
 
         public Builder(int customPowerComponentCount, int customTimeComponentCount,
@@ -113,6 +166,25 @@
         }
 
         /**
+         * Sets the duration, in milliseconds, that this UID was active in a particular state,
+         * such as foreground or background.
+         */
+        @NonNull
+        public Builder setTimeInStateMs(@State int state, long timeInStateMs) {
+            switch (state) {
+                case STATE_FOREGROUND:
+                    mTimeInForegroundMs = timeInStateMs;
+                    break;
+                case STATE_BACKGROUND:
+                    mTimeInBackgroundMs = timeInStateMs;
+                    break;
+                default:
+                    throw new IllegalArgumentException("Unsupported state: " + state);
+            }
+            return this;
+        }
+
+        /**
          * Marks the UidBatteryConsumer for exclusion from the result set.
          */
         public Builder excludeFromBatteryUsageStats() {
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 8bdfd3d..5069e031 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1688,6 +1688,7 @@
      * @return Whether guest user is always ephemeral
      * @hide
      */
+    @TestApi
     public static boolean isGuestUserEphemeral() {
         return Resources.getSystem()
                 .getBoolean(com.android.internal.R.bool.config_guestUserEphemeral);
@@ -1802,6 +1803,20 @@
     }
 
     /**
+     * @return the user type of the context user.
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.CREATE_USERS
+    })
+    @UserHandleAware
+    public @NonNull String getUserType() {
+        UserInfo userInfo = getUserInfo(mUserId);
+        return userInfo == null ? "" : userInfo.userType;
+    }
+
+    /**
      * Returns the user name of the context user. This call is only available to applications on
      * the system image; it requires the {@code android.permission.MANAGE_USERS} or {@code
      * android.permission.GET_ACCOUNTS_PRIVILEGED} permissions.
@@ -1809,7 +1824,8 @@
      * @return the user name
      */
     @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
-            android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}, conditional = true)
+            android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED,
+            android.Manifest.permission.CREATE_USERS}, conditional = true)
     @UserHandleAware
     public @NonNull String getUserName() {
         if (UserHandle.myUserId() == mUserId) {
@@ -2300,13 +2316,14 @@
     }
 
     /**
-     * Checks if the calling user is running on foreground.
+     * Checks if the context user is running in the foreground.
      *
-     * @return whether the calling user is running on foreground.
+     * @return whether the context user is running in the foreground.
      */
+    @UserHandleAware
     public boolean isUserForeground() {
         try {
-            return mService.isUserForeground();
+            return mService.isUserForeground(mUserId);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
@@ -2792,6 +2809,7 @@
      */
     @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
             Manifest.permission.CREATE_USERS})
+    @TestApi
     public @Nullable UserInfo createUser(@Nullable String name, @NonNull String userType,
             @UserInfoFlag int flags) {
         try {
@@ -2828,6 +2846,7 @@
      * @throws UserOperationException if the user could not be created.
      * @hide
      */
+    @TestApi
     @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
             Manifest.permission.CREATE_USERS})
     public @NonNull UserInfo preCreateUser(@NonNull String userType)
@@ -2976,10 +2995,11 @@
      *
      * @hide
      */
+    @TestApi
     @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
             Manifest.permission.CREATE_USERS})
-    public UserInfo createProfileForUser(String name, @NonNull String userType,
-            @UserInfoFlag int flags, @UserIdInt int userId, String[] disallowedPackages) {
+    public @Nullable UserInfo createProfileForUser(@Nullable String name, @NonNull String userType,
+            @UserInfoFlag int flags, @UserIdInt int userId, @Nullable String[] disallowedPackages) {
         try {
             return mService.createProfileForUserWithThrow(name, userType, flags, userId,
                     disallowedPackages);
@@ -3022,9 +3042,10 @@
      *
      * @hide
      */
+    @TestApi
     @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
             Manifest.permission.CREATE_USERS})
-    public UserInfo createRestrictedProfile(String name) {
+    public @Nullable UserInfo createRestrictedProfile(@Nullable String name) {
         try {
             UserHandle parentUserHandle = Process.myUserHandle();
             UserInfo user = mService.createRestrictedProfileWithThrow(name,
@@ -3248,10 +3269,11 @@
 
     /**
      * Return the number of users currently created on the device.
-     * <p>This API is not for use by third-party apps. It requires the {@code MANAGE_USERS}
-     * permission.</p>
      */
-    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.CREATE_USERS
+    })
     public int getUserCount() {
         List<UserInfo> users = getUsers();
         return users != null ? users.size() : 1;
@@ -3274,7 +3296,10 @@
      * @hide
      */
     @UnsupportedAppUsage
-    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.CREATE_USERS
+    })
     public List<UserInfo> getUsers() {
         return getUsers(/*excludePartial= */ true, /* excludeDying= */ false,
                 /* excludePreCreated= */ true);
@@ -3292,7 +3317,10 @@
      * @return the list of users that were created.
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.CREATE_USERS
+    })
     public @NonNull List<UserInfo> getAliveUsers() {
         return getUsers(/*excludePartial= */ true, /* excludeDying= */ true,
                 /* excludePreCreated= */ true);
@@ -3306,7 +3334,10 @@
      */
     @Deprecated
     @UnsupportedAppUsage
-    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.CREATE_USERS
+    })
     public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
         return getUsers(/*excludePartial= */ true, excludeDying,
                 /* excludePreCreated= */ true);
@@ -3317,8 +3348,12 @@
      *
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
-    public List<UserInfo> getUsers(boolean excludePartial, boolean excludeDying,
+    @TestApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.CREATE_USERS
+    })
+    public @NonNull List<UserInfo> getUsers(boolean excludePartial, boolean excludeDying,
             boolean excludePreCreated) {
         try {
             return mService.getUsers(excludePartial, excludeDying, excludePreCreated);
@@ -3335,7 +3370,10 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.CREATE_USERS
+    })
     public @NonNull List<UserHandle> getUserHandles(boolean excludeDying) {
         List<UserInfo> users = getUsers(/* excludePartial= */ true, excludeDying,
                 /* excludePreCreated= */ true);
@@ -3354,7 +3392,10 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.CREATE_USERS
+    })
     public long[] getSerialNumbersOfUsers(boolean excludeDying) {
         List<UserInfo> users = getUsers(/* excludePartial= */ true, excludeDying,
                 /* excludePreCreated= */ true);
@@ -3678,7 +3719,10 @@
      * @hide
      */
     @UnsupportedAppUsage
-    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.INTERACT_ACROSS_USERS
+    })
     public UserInfo getProfileParent(@UserIdInt int userId) {
         try {
             return mService.getProfileParent(userId);
@@ -3697,7 +3741,10 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.INTERACT_ACROSS_USERS
+    })
     public @Nullable UserHandle getProfileParent(@NonNull UserHandle user) {
         UserInfo info = getProfileParent(user.getIdentifier());
 
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 06203ff..9ffc5aa0 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -426,7 +426,7 @@
         // avoid writing a partial response to the zygote.
         for (String arg : args) {
             // Making two indexOf calls here is faster than running a manually fused loop due
-            // to the fact that indexOf is a optimized intrinsic.
+            // to the fact that indexOf is an optimized intrinsic.
             if (arg.indexOf('\n') >= 0) {
                 throw new ZygoteStartFailedEx("Embedded newlines not allowed");
             } else if (arg.indexOf('\r') >= 0) {
diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java
index cec6a1f..87dced8 100644
--- a/core/java/android/os/incremental/IncrementalManager.java
+++ b/core/java/android/os/incremental/IncrementalManager.java
@@ -155,22 +155,21 @@
     }
 
     /**
-     * Set up an app's code path. The expected outcome of this method is:
+     * Link an app's files from the stage dir to the final installation location.
+     * The expected outcome of this method is:
      * 1) The actual apk directory under /data/incremental is bind-mounted to the parent directory
      * of {@code afterCodeFile}.
      * 2) All the files under {@code beforeCodeFile} will show up under {@code afterCodeFile}.
      *
      * @param beforeCodeFile Path that is currently bind-mounted and have APKs under it.
-     *                       Should no longer have any APKs after this method is called.
      *                       Example: /data/app/vmdl*tmp
      * @param afterCodeFile Path that should will have APKs after this method is called. Its parent
      *                      directory should be bind-mounted to a directory under /data/incremental.
      *                      Example: /data/app/~~[randomStringA]/[packageName]-[randomStringB]
      * @throws IllegalArgumentException
      * @throws IOException
-     * TODO(b/147371381): add unit tests
      */
-    public void renameCodePath(File beforeCodeFile, File afterCodeFile)
+    public void linkCodePath(File beforeCodeFile, File afterCodeFile)
             throws IllegalArgumentException, IOException {
         final File beforeCodeAbsolute = beforeCodeFile.getAbsoluteFile();
         final IncrementalStorage apkStorage = openStorage(beforeCodeAbsolute.toString());
@@ -188,7 +187,6 @@
         try {
             final String afterCodePathName = afterCodeFile.getName();
             linkFiles(apkStorage, beforeCodeAbsolute, "", linkedApkStorage, afterCodePathName);
-            apkStorage.unBind(beforeCodeAbsolute.toString());
         } catch (Exception e) {
             linkedApkStorage.unBind(targetStorageDir);
             throw e;
@@ -241,10 +239,12 @@
     }
 
     /**
-     * Checks if device supports V2 calls (e.g. PerUid).
+     * 0 - IncFs is disabled.
+     * 1 - IncFs v1, core features, no PerUid support. Optional in R.
+     * 2 - IncFs v2, PerUid support, fs-verity support. Required in S.
      */
-    public static boolean isV2Available() {
-        return nativeIsV2Available();
+    public static int getVersion() {
+        return nativeIsEnabled() ? nativeIsV2Available() ? 2 : 1 : 0;
     }
 
     /**
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 4669b20..98b4e0b 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -28,6 +28,8 @@
 import android.os.storage.VolumeInfo;
 import android.os.storage.VolumeRecord;
 import com.android.internal.os.AppFuseMount;
+import android.app.PendingIntent;
+
 
 /**
  * WARNING! Update IMountService.h and IMountService.cpp if you change this
@@ -196,4 +198,7 @@
     void clearUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 88;
     void fixupAppDir(in String path) = 89;
     void disableAppDataIsolation(in String pkgName, int pid, int userId) = 90;
-}
+    void notifyAppIoBlocked(in String volumeUuid, int uid, int tid, int reason) = 91;
+    void notifyAppIoResumed(in String volumeUuid, int uid, int tid, int reason) = 92;
+    PendingIntent getManageSpaceActivityIntent(in String packageName, int requestCode) = 93;
+    }
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 3a5426c..c967deb 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -49,6 +49,7 @@
 import android.app.ActivityThread;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
+import android.app.PendingIntent;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -701,6 +702,33 @@
         }
     }
 
+    /**
+     * Returns a {@link PendingIntent} that can be used by Apps with
+     * {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} permission
+     * to launch the manageSpaceActivity for any App that implements it, irrespective of its
+     * exported status.
+     * <p>
+     * Caller has the responsibility of supplying a valid packageName which has
+     * manageSpaceActivity implemented.
+     *
+     * @param packageName package name for the App for which manageSpaceActivity is to be launched
+     * @param requestCode for launching the activity
+     * @return PendingIntent to launch the manageSpaceActivity if successful, null if the
+     * packageName doesn't have a manageSpaceActivity.
+     * @throws IllegalArgumentException an invalid packageName is supplied.
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_EXTERNAL_STORAGE)
+    @Nullable
+    public PendingIntent getManageSpaceActivityIntent(
+            @NonNull String packageName, int requestCode) {
+        try {
+            return mStorageManager.getManageSpaceActivityIntent(packageName,
+                    requestCode);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     private ObbInfo getObbInfo(String canonicalPath) {
         try {
             final ObbInfo obbInfo = ObbScanner.getObbInfo(canonicalPath);
@@ -2699,6 +2727,82 @@
         }
     }
 
+    /**
+     * Reason to provide if app IO is blocked/resumed because of transcoding
+     *
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static final int APP_IO_BLOCKED_REASON_TRANSCODING = 0;
+
+    /**
+     * Constants for use with
+     * {@link #notifyAppIoBlocked} and {@link notifyAppIoResumed}, to specify the reason an app's
+     * IO is blocked/resumed.
+     *
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "APP_IO_BLOCKED_REASON_" }, value = {
+            APP_IO_BLOCKED_REASON_TRANSCODING
+    })
+    public @interface AppIoBlockedReason {}
+
+    /**
+     * Notify the system that an app with {@code uid} and {@code tid} is blocked on an IO request on
+     * {@code volumeUuid} for {@code reason}.
+     *
+     * This blocked state can be used to modify the ANR behavior for the app while it's blocked.
+     * For example during transcoding.
+     *
+     * This can only be called by the {@link ExternalStorageService} holding the
+     * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE} permission.
+     *
+     * @param volumeUuid the UUID of the storage volume that the app IO is blocked on
+     * @param uid the UID of the app blocked on IO
+     * @param tid the tid of the app blocked on IO
+     * @param reason the reason the app is blocked on IO
+     *
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public void notifyAppIoBlocked(@NonNull UUID volumeUuid, int uid, int tid,
+            @AppIoBlockedReason int reason) {
+        Objects.requireNonNull(volumeUuid);
+        try {
+            mStorageManager.notifyAppIoBlocked(convert(volumeUuid), uid, tid, reason);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Notify the system that an app with {@code uid} and {@code tid} has resmued a previously
+     * blocked IO request on {@code volumeUuid} for {@code reason}.
+     *
+     * All app IO will be automatically marked as unblocked if {@code volumeUuid} is unmounted.
+     *
+     * This can only be called by the {@link ExternalStorageService} holding the
+     * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE} permission.
+     *
+     * @param volumeUuid the UUID of the storage volume that the app IO is resumed on
+     * @param uid the UID of the app resuming IO
+     * @param tid the tid of the app resuming IO
+     * @param reason the reason the app is resuming IO
+     *
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public void notifyAppIoResumed(@NonNull UUID volumeUuid, int uid, int tid,
+            @AppIoBlockedReason int reason) {
+        Objects.requireNonNull(volumeUuid);
+        try {
+            mStorageManager.notifyAppIoResumed(convert(volumeUuid), uid, tid, reason);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     private final Object mFuseAppLoopLock = new Object();
 
     @GuardedBy("mFuseAppLoopLock")
diff --git a/core/java/android/os/strictmode/IncorrectContextUseViolation.java b/core/java/android/os/strictmode/IncorrectContextUseViolation.java
index 11d26ca..d8c22fd 100644
--- a/core/java/android/os/strictmode/IncorrectContextUseViolation.java
+++ b/core/java/android/os/strictmode/IncorrectContextUseViolation.java
@@ -24,7 +24,7 @@
  * instance.
  *
  * @see Context#getSystemService(String)
- * @see Context#isUiContext(Context)
+ * @see Context#isUiContext
  * @see android.os.StrictMode.VmPolicy.Builder#detectIncorrectContextUse()
  */
 public final class IncorrectContextUseViolation extends Violation {
diff --git a/core/java/android/permission/OWNERS b/core/java/android/permission/OWNERS
index b323468..19a3a8b 100644
--- a/core/java/android/permission/OWNERS
+++ b/core/java/android/permission/OWNERS
@@ -1,7 +1,13 @@
 # Bug component: 137825
 
+eugenesusla@google.com
 evanseverson@google.com
+evanxinchen@google.com
+ewol@google.com
+guojing@google.com
+jaysullivan@google.com
 ntmyren@google.com
-zhanghai@google.com
 svetoslavganov@android.com
 svetoslavganov@google.com
+theianchen@google.com
+zhanghai@google.com
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index ff01011..bae36b29 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -485,10 +485,6 @@
      * One for cases where the installer of the package allowlists a permission. This list
      * corresponds to the {@link PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER} flag. Can be
      * accessed by pre-installed holders of a dedicated permission or the installer on record.
-     * <li>
-     * One for cases where the system exempts the permission when granting a role. This list
-     * corresponds to the {@link PackageManager#FLAG_PERMISSION_ALLOWLIST_ROLE} flag. Can be
-     * accessed by pre-installed holders of a dedicated permission.
      * </ol>
      *
      * @param packageName the app for which to get allowlisted permissions
@@ -502,7 +498,6 @@
      * @see PackageManager#FLAG_PERMISSION_WHITELIST_SYSTEM
      * @see PackageManager#FLAG_PERMISSION_WHITELIST_UPGRADE
      * @see PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER
-     * @see PackageManager#FLAG_PERMISSION_ALLOWLIST_ROLE
      *
      * @hide Pending API
      */
@@ -549,10 +544,6 @@
      * One for cases where the installer of the package allowlists a permission. This list
      * corresponds to the {@link PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER} flag. Can be
      * accessed by pre-installed holders of a dedicated permission or the installer on record.
-     * <li>
-     * One for cases where the system exempts the permission when granting a role. This list
-     * corresponds to the {@link PackageManager#FLAG_PERMISSION_ALLOWLIST_ROLE} flag. Can be
-     * accessed by pre-installed holders of a dedicated permission.
      * </ol>
      * <p>
      * You need to specify the allowlists for which to set the allowlisted permissions which will
@@ -570,7 +561,6 @@
      * @see PackageManager#FLAG_PERMISSION_WHITELIST_SYSTEM
      * @see PackageManager#FLAG_PERMISSION_WHITELIST_UPGRADE
      * @see PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER
-     * @see PackageManager#FLAG_PERMISSION_ALLOWLIST_ROLE
      *
      * @hide Pending API
      */
@@ -613,10 +603,6 @@
      * One for cases where the installer of the package allowlists a permission. This list
      * corresponds to the {@link PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER} flag. Can be
      * accessed by pre-installed holders of a dedicated permission or the installer on record.
-     * <li>
-     * One for cases where the system exempts the permission when granting a role. This list
-     * corresponds to the {@link PackageManager#FLAG_PERMISSION_ALLOWLIST_ROLE} flag. Can be
-     * accessed by pre-installed holders of a dedicated permission.
      * </ol>
      * <p>
      * You need to specify the allowlists for which to set the allowlisted permissions which will
@@ -634,7 +620,6 @@
      * @see PackageManager#FLAG_PERMISSION_WHITELIST_SYSTEM
      * @see PackageManager#FLAG_PERMISSION_WHITELIST_UPGRADE
      * @see PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER
-     * @see PackageManager#FLAG_PERMISSION_ALLOWLIST_ROLE
      *
      * @hide Pending API
      */
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 0e35ef9..4c9e77c 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -57,6 +57,8 @@
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
 
+import com.android.internal.R;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -186,6 +188,15 @@
                 == PackageManager.PERMISSION_GRANTED;
     }
 
+    private boolean isSpeechRecognizerUsage(String op, String packageName) {
+        if (!OPSTR_RECORD_AUDIO.equals(op)) {
+            return false;
+        }
+
+        return packageName.equals(
+                mContext.getString(R.string.config_systemSpeechRecognizer));
+    }
+
     /**
      * @see PermissionManager.getIndicatorAppOpUsageData
      */
@@ -317,7 +328,8 @@
                     if (packageName.equals(SYSTEM_PKG)
                             || (!isUserSensitive(packageName, user, op)
                             && !isLocationProvider(packageName, user)
-                            && !isAppPredictor(packageName, user))) {
+                            && !isAppPredictor(packageName, user))
+                            && !isSpeechRecognizerUsage(op, packageName)) {
                         continue;
                     }
 
diff --git a/core/java/android/permissionpresenterservice/OWNERS b/core/java/android/permissionpresenterservice/OWNERS
index b323468..fb6099c 100644
--- a/core/java/android/permissionpresenterservice/OWNERS
+++ b/core/java/android/permissionpresenterservice/OWNERS
@@ -1,7 +1,3 @@
 # Bug component: 137825
 
-evanseverson@google.com
-ntmyren@google.com
-zhanghai@google.com
-svetoslavganov@android.com
-svetoslavganov@google.com
+include platform/frameworks/base:/core/java/android/permission/OWNERS
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 4354920..6e89faf 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -157,6 +157,14 @@
     public static final String NAMESPACE_BLUETOOTH = "bluetooth";
 
     /**
+     * Namespace for features relating to clipboard.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_CLIPBOARD = "clipboard";
+
+    /**
      * Namespace for all networking connectivity related features.
      *
      * @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d50dc7f..85cef84 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -417,6 +417,22 @@
             "android.settings.MANAGE_UNKNOWN_APP_SOURCES";
 
     /**
+     * Activity Action: Show settings to allow configuration of
+     * {@link Manifest.permission#SCHEDULE_EXACT_ALARM} permission
+     *
+     * Input: Optionally, the Intent's data URI can specify the application package name to
+     * directly invoke the management GUI specific to the package name. For example
+     * "package:com.my.app".
+     * <p>
+     * Output: When a package data uri is passed as input, the activity result is set to
+     * {@link android.app.Activity#RESULT_OK} if the permission was granted to the app. Otherwise,
+     * the result is set to {@link android.app.Activity#RESULT_CANCELED}.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_REQUEST_SCHEDULE_EXACT_ALARM =
+            "android.settings.REQUEST_SCHEDULE_EXACT_ALARM";
+
+    /**
      * Activity Action: Show settings to allow configuration of cross-profile access for apps
      *
      * Input: Optionally, the Intent's data URI can specify the application package name to
@@ -10496,18 +10512,6 @@
                 "force_desktop_mode_on_external_displays";
 
         /**
-         * Whether to allow non-resizable apps to be freeform.
-         *
-         * TODO(b/176061101) remove after update all usages
-         * @deprecated use {@link #DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW}
-         * @hide
-         */
-        @Deprecated
-        @Readable
-        public static final String DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM =
-                "enable_sizecompat_freeform";
-
-        /**
          * Whether to allow non-resizable apps to be shown in multi-window. The app will be
          * letterboxed if the request orientation is not met, and will be shown in size-compat
          * mode if the container size has changed.
@@ -14606,6 +14610,29 @@
         public static final String POWER_BUTTON_VERY_LONG_PRESS =
                 "power_button_very_long_press";
 
+
+        /**
+         * Keyguard should be on the left hand side of the screen, for wide screen layouts.
+         *
+         * @hide
+         */
+        public static final int ONE_HANDED_KEYGUARD_SIDE_LEFT = 0;
+
+        /**
+         * Keyguard should be on the right hand side of the screen, for wide screen layouts.
+         *
+         * @hide
+         */
+        public static final int ONE_HANDED_KEYGUARD_SIDE_RIGHT = 1;
+        /**
+         * In one handed mode, which side the keyguard should be on. Allowable values are one of
+         * the ONE_HANDED_KEYGUARD_SIDE_* constants.
+         *
+         * @hide
+         */
+        @Readable
+        public static final String ONE_HANDED_KEYGUARD_SIDE = "one_handed_keyguard_side";
+
         /**
          * Keys we no longer back up under the current schema, but want to continue to
          * process when restoring historical backup datasets.
@@ -16537,30 +16564,6 @@
 
     /**
      * Performs a strict and comprehensive check of whether a calling package is allowed to
-     * change the state of network, as the condition differs for pre-M, M+, and
-     * privileged/preinstalled apps. The caller is expected to have either the
-     * CHANGE_NETWORK_STATE or the WRITE_SETTINGS permission declared. Either of these
-     * permissions allow changing network state; WRITE_SETTINGS is a runtime permission and
-     * can be revoked, but (except in M, excluding M MRs), CHANGE_NETWORK_STATE is a normal
-     * permission and cannot be revoked. See http://b/23597341
-     *
-     * Note: if the check succeeds because the application holds WRITE_SETTINGS, the operation
-     * of this app will be updated to the current time.
-     * @hide
-     */
-    public static boolean checkAndNoteChangeNetworkStateOperation(Context context, int uid,
-            String callingPackage, String callingAttributionTag, boolean throwException) {
-        if (context.checkCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE)
-                == PackageManager.PERMISSION_GRANTED) {
-            return true;
-        }
-        return isCallingPackageAllowedToPerformAppOpsProtectedOperation(context, uid,
-                callingPackage, callingAttributionTag, throwException,
-                AppOpsManager.OP_WRITE_SETTINGS, PM_CHANGE_NETWORK_STATE, true);
-    }
-
-    /**
-     * Performs a strict and comprehensive check of whether a calling package is allowed to
      * draw on top of other apps, as the conditions differs for pre-M, M+, and
      * privileged/preinstalled apps. If the provided uid does not match the callingPackage,
      * a negative result will be returned.
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 7996f09..8a4812a 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -5302,5 +5302,13 @@
          * @hide
          */
         public static final String COLUMN_RCS_CONFIG = "rcs_config";
+
+        /**
+         * TelephonyProvider column name for VoIMS provisioning. Default is 0.
+         * <P>Type: INTEGER </P>
+         *
+         * @hide
+         */
+        public static final String COLUMN_VOIMS_OPT_IN_STATUS = "voims_opt_in_status";
     }
 }
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index d859b1c..6788353 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -27,8 +27,11 @@
 import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
 import android.security.KeyStore;
-import android.security.keystore.AndroidKeyStoreProvider;
+import android.security.KeyStore2;
 import android.security.keystore.KeyPermanentlyInvalidatedException;
+import android.security.keystore2.AndroidKeyStoreProvider;
+import android.system.keystore2.Domain;
+import android.system.keystore2.KeyDescriptor;
 
 import com.android.internal.widget.ILockSettings;
 
@@ -709,10 +712,34 @@
      */
     @NonNull Key getKeyFromGrant(@NonNull String grantAlias)
             throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
-        return AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore(
-                mKeyStore,
-                grantAlias,
-                KeyStore.UID_SELF);
+        if (grantAlias.startsWith(APPLICATION_KEY_GRANT_PREFIX)) {
+            return AndroidKeyStoreProvider
+                    .loadAndroidKeyStoreSecretKeyFromKeystore(
+                            KeyStore2.getInstance(),
+                            getGrantDescriptor(grantAlias));
+        }
+        // TODO(b/171305545): remove KeyStore1 logic.
+        return android.security.keystore.AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore(
+            mKeyStore,
+            grantAlias,
+            KeyStore.UID_SELF);
+
+    }
+
+    private static final String APPLICATION_KEY_GRANT_PREFIX = "recoverable_key:";
+
+    private static @Nullable KeyDescriptor getGrantDescriptor(String grantAlias) {
+        KeyDescriptor result = new KeyDescriptor();
+        result.domain = Domain.GRANT;
+        result.blob = null;
+        result.alias = null;
+        try {
+            result.nspace = Long.parseUnsignedLong(
+                    grantAlias.substring(APPLICATION_KEY_GRANT_PREFIX.length()), 16);
+        } catch (NumberFormatException e) {
+            return null;
+        }
+        return result;
     }
 
     /**
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 73e66d0..7aa5bbc9 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -85,6 +85,10 @@
  *               android:name="android.service.notification.default_filter_types"
  *               android:value="1,2">
  *           &lt;/meta-data>
+ *     &lt;meta-data
+ *               android:name="android.service.notification.disabled_filter_types"
+ *               android:value="2">
+ *           &lt;/meta-data>
  * &lt;/service></pre>
  *
  * <p>The service should wait for the {@link #onListenerConnected()} event
@@ -123,6 +127,19 @@
             = "android.service.notification.default_filter_types";
 
     /**
+     * The name of the {@code meta-data} tag containing a comma separated list of default
+     * integer notification types that this listener never wants to receive. See
+     * {@link #FLAG_FILTER_TYPE_ONGOING},
+     * {@link #FLAG_FILTER_TYPE_CONVERSATIONS}, {@link #FLAG_FILTER_TYPE_ALERTING),
+     * and {@link #FLAG_FILTER_TYPE_SILENT}.
+     * <p>Types provided in this list will appear as 'off' and 'disabled' in the user interface,
+     * so users don't enable a type that the listener will never bridge to their paired devices.</p>
+     *
+     */
+    public static final String META_DATA_DISABLED_FILTER_TYPES
+            = "android.service.notification.disabled_filter_types";
+
+    /**
      * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
      *     Normal interruption filter.
      */
diff --git a/core/java/android/service/storage/ExternalStorageService.java b/core/java/android/service/storage/ExternalStorageService.java
index 87add57..1e07a87 100644
--- a/core/java/android/service/storage/ExternalStorageService.java
+++ b/core/java/android/service/storage/ExternalStorageService.java
@@ -102,14 +102,6 @@
      */
     public static final String EXTRA_PACKAGE_NAME = "android.service.storage.extra.package_name";
 
-    /**
-     * {@link Bundle} key for a {@link Long} value.
-     *
-     * {@hide}
-     */
-    public static final String EXTRA_ANR_TIMEOUT_MS =
-            "android.service.storage.extra.anr_timeout_ms";
-
     /** @hide */
     @IntDef(flag = true, prefix = {"FLAG_SESSION_"},
         value = {FLAG_SESSION_TYPE_FUSE, FLAG_SESSION_ATTRIBUTE_INDEXABLE})
@@ -178,12 +170,12 @@
     }
 
     /**
-     * Called when {@code packageName} is about to ANR
+     * Called when {@code packageName} is about to ANR. The {@link ExternalStorageService} can
+     * show a progress dialog for the {@code reason}.
      *
-     * @return ANR dialog delay in milliseconds
      */
-    public long onGetAnrDelayMillis(@NonNull String packageName, int uid) {
-        throw new UnsupportedOperationException("onGetAnrDelayMillis not implemented");
+    public void onAnrDelayStarted(@NonNull String packageName, int uid, int tid, int reason) {
+        throw new UnsupportedOperationException("onAnrDelayStarted not implemented");
     }
 
     @Override
@@ -247,14 +239,14 @@
         }
 
         @Override
-        public void getAnrDelayMillis(String packageName, int uid, RemoteCallback callback)
-                throws RemoteException {
+        public void notifyAnrDelayStarted(String packageName, int uid, int tid, int reason,
+                RemoteCallback callback) throws RemoteException {
             mHandler.post(() -> {
                 try {
-                    long timeoutMs = onGetAnrDelayMillis(packageName, uid);
-                    sendTimeoutResult(packageName, timeoutMs, null /* throwable */, callback);
+                    onAnrDelayStarted(packageName, uid, tid, reason);
+                    sendResult(packageName, null /* throwable */, callback);
                 } catch (Throwable t) {
-                    sendTimeoutResult(packageName, 0 /* timeoutMs */, t, callback);
+                    sendResult(packageName, t, callback);
                 }
             });
         }
@@ -267,16 +259,5 @@
             }
             callback.sendResult(bundle);
         }
-
-        private void sendTimeoutResult(String packageName, long timeoutMs, Throwable throwable,
-                RemoteCallback callback) {
-            Bundle bundle = new Bundle();
-            bundle.putString(EXTRA_PACKAGE_NAME, packageName);
-            bundle.putLong(EXTRA_ANR_TIMEOUT_MS, timeoutMs);
-            if (throwable != null) {
-                bundle.putParcelable(EXTRA_ERROR, new ParcelableException(throwable));
-            }
-            callback.sendResult(bundle);
-        }
     }
 }
diff --git a/core/java/android/service/storage/IExternalStorageService.aidl b/core/java/android/service/storage/IExternalStorageService.aidl
index 2e0bd86..ba98efa 100644
--- a/core/java/android/service/storage/IExternalStorageService.aidl
+++ b/core/java/android/service/storage/IExternalStorageService.aidl
@@ -32,5 +32,6 @@
         in RemoteCallback callback);
     void freeCache(@utf8InCpp String sessionId, in String volumeUuid, long bytes,
         in RemoteCallback callback);
-    void getAnrDelayMillis(String packageName, int uid, in RemoteCallback callback);
+    void notifyAnrDelayStarted(String packageName, int uid, int tid, int reason,
+         in RemoteCallback callback);
 }
\ No newline at end of file
diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java
index 3c35d2c..7f1c5ff 100644
--- a/core/java/android/service/voice/HotwordDetectionService.java
+++ b/core/java/android/service/voice/HotwordDetectionService.java
@@ -19,15 +19,18 @@
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 
 import android.annotation.CallSuper;
+import android.annotation.DurationMillisLong;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
 import android.app.Service;
 import android.content.Intent;
+import android.media.AudioFormat;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -57,14 +60,21 @@
 
     private final IHotwordDetectionService mInterface = new IHotwordDetectionService.Stub() {
         @Override
-        public void detectFromDspSource(int sessionId, IDspHotwordDetectionCallback callback)
+        public void detectFromDspSource(
+                ParcelFileDescriptor audioStream,
+                AudioFormat audioFormat,
+                long timeoutMillis,
+                IDspHotwordDetectionCallback callback)
                 throws RemoteException {
             if (DBG) {
                 Log.d(TAG, "#detectFromDspSource");
             }
             mHandler.sendMessage(obtainMessage(HotwordDetectionService::onDetectFromDspSource,
                     HotwordDetectionService.this,
-                    sessionId, new DspHotwordDetectionCallback(callback)));
+                    audioStream,
+                    audioFormat,
+                    timeoutMillis,
+                    new DspHotwordDetectionCallback(callback)));
         }
     };
 
@@ -89,15 +99,24 @@
     /**
      * Detect the audio data generated from Dsp.
      *
-     * @param sessionId The session to use when attempting to capture more audio from the DSP
-     *                  hardware.
+     * <p>Note: the clients are supposed to call {@code close} on the input stream when they are
+     * done with the operation in order to free up resources.
+     *
+     * @param audioStream Stream containing audio bytes returned from DSP
+     * @param audioFormat Format of the supplied audio
+     * @param timeoutMillis Timeout in milliseconds for the operation to invoke the callback. If
+     *                      the application fails to abide by the timeout, system will close the
+     *                      microphone and cancel the operation.
      * @param callback Use {@link HotwordDetectionService#DspHotwordDetectionCallback} to return
      * the detected result.
      *
      * @hide
      */
     @SystemApi
-    public void onDetectFromDspSource(int sessionId,
+    public void onDetectFromDspSource(
+            @NonNull ParcelFileDescriptor audioStream,
+            @NonNull AudioFormat audioFormat,
+            @DurationMillisLong long timeoutMillis,
             @NonNull DspHotwordDetectionCallback callback) {
     }
 
diff --git a/core/java/android/service/voice/IHotwordDetectionService.aidl b/core/java/android/service/voice/IHotwordDetectionService.aidl
index 990ad45..cbe76e4 100644
--- a/core/java/android/service/voice/IHotwordDetectionService.aidl
+++ b/core/java/android/service/voice/IHotwordDetectionService.aidl
@@ -16,6 +16,8 @@
 
 package android.service.voice;
 
+import android.media.AudioFormat;
+import android.os.ParcelFileDescriptor;
 import android.service.voice.IDspHotwordDetectionCallback;
 
 /**
@@ -24,5 +26,9 @@
  * @hide
  */
 oneway interface IHotwordDetectionService {
-    void detectFromDspSource(int sessionId, in IDspHotwordDetectionCallback callback);
+    void detectFromDspSource(
+    in ParcelFileDescriptor audioStream,
+    in AudioFormat audioFormat,
+    long timeoutMillis,
+    in IDspHotwordDetectionCallback callback);
 }
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index ffb4a6e..3c355d4 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -270,13 +270,13 @@
     /**
      * Notify call state changed on certain subscription.
      *
-     * @param subId for which call state changed.
      * @param slotIndex for which call state changed. Can be derived from subId except when subId is
      * invalid.
+     * @param subId for which call state changed.
      * @param state latest call state. e.g, offhook, ringing
      * @param incomingNumber incoming phone number.
      */
-    public void notifyCallStateChanged(int subId, int slotIndex, @CallState int state,
+    public void notifyCallStateChanged(int slotIndex, int subId, @CallState int state,
             @Nullable String incomingNumber) {
         try {
             sRegistry.notifyCallState(slotIndex, subId, state, incomingNumber);
@@ -329,12 +329,12 @@
     /**
      * Notify {@link ServiceState} update on certain subscription.
      *
-     * @param subId for which the service state changed.
      * @param slotIndex for which the service state changed. Can be derived from subId except
      * subId is invalid.
+     * @param subId for which the service state changed.
      * @param state service state e.g, in service, out of service or roaming status.
      */
-    public void notifyServiceStateChanged(int subId, int slotIndex, @NonNull ServiceState state) {
+    public void notifyServiceStateChanged(int slotIndex, int subId, @NonNull ServiceState state) {
         try {
             sRegistry.notifyServiceStateForPhoneId(slotIndex, subId, state);
         } catch (RemoteException ex) {
@@ -345,12 +345,12 @@
     /**
      * Notify {@link SignalStrength} update on certain subscription.
      *
-     * @param subId for which the signalstrength changed.
      * @param slotIndex for which the signalstrength changed. Can be derived from subId except when
      * subId is invalid.
+     * @param subId for which the signalstrength changed.
      * @param signalStrength e.g, signalstrength level {@see SignalStrength#getLevel()}
      */
-    public void notifySignalStrengthChanged(int subId, int slotIndex,
+    public void notifySignalStrengthChanged(int slotIndex, int subId,
             @NonNull SignalStrength signalStrength) {
         try {
             sRegistry.notifySignalStrengthForPhoneId(slotIndex, subId, signalStrength);
@@ -363,13 +363,13 @@
      * Notify changes to the message-waiting indicator on certain subscription. e.g, The status bar
      * uses message waiting indicator to determine when to display the voicemail icon.
      *
-     * @param subId for which message waiting indicator changed.
      * @param slotIndex for which message waiting indicator changed. Can be derived from subId
      * except when subId is invalid.
+     * @param subId for which message waiting indicator changed.
      * @param msgWaitingInd {@code true} indicates there is message-waiting indicator, {@code false}
      * otherwise.
      */
-    public void notifyMessageWaitingChanged(int subId, int slotIndex, boolean msgWaitingInd) {
+    public void notifyMessageWaitingChanged(int slotIndex, int subId, boolean msgWaitingInd) {
         try {
             sRegistry.notifyMessageWaitingChangedForPhoneId(slotIndex, subId, msgWaitingInd);
         } catch (RemoteException ex) {
@@ -410,9 +410,9 @@
     /**
      * Notify changes to default (Internet) data connection state on certain subscription.
      *
-     * @param subId for which data connection state changed.
      * @param slotIndex for which data connections state changed. Can be derived from subId except
      * when subId is invalid.
+     * @param subId for which data connection state changed.
      * @param preciseState the PreciseDataConnectionState
      *
      * @see PreciseDataConnectionState
@@ -431,13 +431,13 @@
     /**
      * Notify {@link CallQuality} change on certain subscription.
      *
-     * @param subId for which call quality state changed.
      * @param slotIndex for which call quality state changed. Can be derived from subId except when
      * subId is invalid.
+     * @param subId for which call quality state changed.
      * @param callQuality Information about call quality e.g, call quality level
      * @param networkType associated with this data connection. e.g, LTE
      */
-    public void notifyCallQualityChanged(int subId, int slotIndex, @NonNull CallQuality callQuality,
+    public void notifyCallQualityChanged(int slotIndex, int subId, @NonNull CallQuality callQuality,
         @NetworkType int networkType) {
         try {
             sRegistry.notifyCallQualityChanged(callQuality, slotIndex, subId, networkType);
@@ -449,11 +449,11 @@
     /**
      * Notify emergency number list changed on certain subscription.
      *
-     * @param subId for which emergency number list changed.
      * @param slotIndex for which emergency number list changed. Can be derived from subId except
      * when subId is invalid.
+     * @param subId for which emergency number list changed.
      */
-    public void notifyEmergencyNumberList(int subId, int slotIndex) {
+    public void notifyEmergencyNumberList( int slotIndex, int subId) {
         try {
             sRegistry.notifyEmergencyNumberList(slotIndex, subId);
         } catch (RemoteException ex) {
@@ -494,13 +494,13 @@
     /**
      * Notify radio power state changed on certain subscription.
      *
-     * @param subId for which radio power state changed.
      * @param slotIndex for which radio power state changed. Can be derived from subId except when
      * subId is invalid.
+     * @param subId for which radio power state changed.
      * @param radioPowerState the current modem radio state.
      */
-    public void notifyRadioPowerStateChanged(int subId, int slotIndex,
-        @RadioPowerState int radioPowerState) {
+    public void notifyRadioPowerStateChanged(int slotIndex, int subId,
+            @RadioPowerState int radioPowerState) {
         try {
             sRegistry.notifyRadioPowerStateChanged(slotIndex, subId, radioPowerState);
         } catch (RemoteException ex) {
@@ -538,13 +538,13 @@
      * Notify data activation state changed on certain subscription.
      * @see TelephonyManager#getDataActivationState()
      *
-     * @param subId for which data activation state changed.
      * @param slotIndex for which data activation state changed. Can be derived from subId except
      * when subId is invalid.
+     * @param subId for which data activation state changed.
      * @param activationState sim activation state e.g, activated.
      */
-    public void notifyDataActivationStateChanged(int subId, int slotIndex,
-        @SimActivationState int activationState) {
+    public void notifyDataActivationStateChanged(int slotIndex, int subId,
+            @SimActivationState int activationState) {
         try {
             sRegistry.notifySimActivationStateChangedForPhoneId(slotIndex, subId,
                     SIM_ACTIVATION_TYPE_DATA, activationState);
@@ -557,13 +557,13 @@
      * Notify voice activation state changed on certain subscription.
      * @see TelephonyManager#getVoiceActivationState()
      *
-     * @param subId for which voice activation state changed.
      * @param slotIndex for which voice activation state changed. Can be derived from subId except
      * subId is invalid.
+     * @param subId for which voice activation state changed.
      * @param activationState sim activation state e.g, activated.
      */
-    public void notifyVoiceActivationStateChanged(int subId, int slotIndex,
-        @SimActivationState int activationState) {
+    public void notifyVoiceActivationStateChanged(int slotIndex, int subId,
+            @SimActivationState int activationState) {
         try {
             sRegistry.notifySimActivationStateChangedForPhoneId(slotIndex, subId,
                     SIM_ACTIVATION_TYPE_VOICE, activationState);
@@ -576,9 +576,9 @@
      * Notify User mobile data state changed on certain subscription. e.g, mobile data is enabled
      * or disabled.
      *
-     * @param subId for which mobile data state has changed.
      * @param slotIndex for which mobile data state has changed. Can be derived from subId except
      * when subId is invalid.
+     * @param subId for which mobile data state has changed.
      * @param state {@code true} indicates mobile data is enabled/on. {@code false} otherwise.
      */
     public void notifyUserMobileDataStateChanged(int slotIndex, int subId, boolean state) {
@@ -599,7 +599,7 @@
      * @param telephonyDisplayInfo The display info.
      */
     public void notifyDisplayInfoChanged(int slotIndex, int subscriptionId,
-                                         @NonNull TelephonyDisplayInfo telephonyDisplayInfo) {
+            @NonNull TelephonyDisplayInfo telephonyDisplayInfo) {
         try {
             sRegistry.notifyDisplayInfoChanged(slotIndex, subscriptionId, telephonyDisplayInfo);
         } catch (RemoteException ex) {
@@ -640,14 +640,14 @@
      * Notify precise call state changed on certain subscription, including foreground, background
      * and ringcall states.
      *
-     * @param subId for which precise call state changed.
      * @param slotIndex for which precise call state changed. Can be derived from subId except when
      * subId is invalid.
+     * @param subId for which precise call state changed.
      * @param ringCallPreciseState ringCall state.
      * @param foregroundCallPreciseState foreground call state.
      * @param backgroundCallPreciseState background call state.
      */
-    public void notifyPreciseCallState(int subId, int slotIndex,
+    public void notifyPreciseCallState(int slotIndex, int subId,
             @PreciseCallStates int ringCallPreciseState,
             @PreciseCallStates int foregroundCallPreciseState,
             @PreciseCallStates int backgroundCallPreciseState) {
@@ -790,9 +790,10 @@
      * @param reason Reason for data enabled/disabled. See {@code REASON_*} in
      * {@link TelephonyManager}.
      */
-    public void notifyDataEnabled(boolean enabled, @TelephonyManager.DataEnabledReason int reason) {
+    public void notifyDataEnabled(int slotIndex, int subId, boolean enabled,
+            @TelephonyManager.DataEnabledReason int reason) {
         try {
-            sRegistry.notifyDataEnabled(enabled, reason);
+            sRegistry.notifyDataEnabled(slotIndex, subId, enabled, reason);
         } catch (RemoteException ex) {
             // system server crash
         }
@@ -801,11 +802,11 @@
     /**
      * Notify emergency number list changed on certain subscription.
      *
-     * @param subId for which emergency number list changed.
      * @param slotIndex for which emergency number list changed. Can be derived from subId except
      * when subId is invalid.
+     * @param subId for which emergency number list changed.
      */
-    public void notifyAllowedNetworkTypesChanged(int subId, int slotIndex,
+    public void notifyAllowedNetworkTypesChanged(int slotIndex, int subId,
             Map<Integer, Long> allowedNetworkTypeList) {
         try {
             sRegistry.notifyAllowedNetworkTypesChanged(slotIndex, subId, allowedNetworkTypeList);
diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java
index aef185c..33b7c75 100644
--- a/core/java/android/text/FontConfig.java
+++ b/core/java/android/text/FontConfig.java
@@ -18,6 +18,7 @@
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
+import android.annotation.CurrentTimeMillisLong;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -101,7 +102,7 @@
      *
      * If there is no update, this return 0.
      */
-    public long getLastModifiedTimeMillis() {
+    public @CurrentTimeMillisLong long getLastModifiedTimeMillis() {
         return mLastModifiedTimeMillis;
     }
 
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index b229212..2b577d0 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -46,6 +46,9 @@
             "settings_do_not_restore_preserved";
     /** @hide */
     public static final String SETTINGS_PROVIDER_MODEL = "settings_provider_model";
+    /** @hide */
+    public static final String SETTINGS_USE_NEW_BACKUP_ELIGIBILITY_RULES
+            = "settings_use_new_backup_eligibility_rules";
 
     private static final Map<String, String> DEFAULT_FLAGS;
 
@@ -68,6 +71,7 @@
         DEFAULT_FLAGS.put("settings_silky_home", "false");
         DEFAULT_FLAGS.put("settings_contextual_home", "false");
         DEFAULT_FLAGS.put(SETTINGS_PROVIDER_MODEL, "false");
+        DEFAULT_FLAGS.put(SETTINGS_USE_NEW_BACKUP_ELIGIBILITY_RULES, "false");
     }
 
     private static final Set<String> PERSISTENT_FLAGS;
diff --git a/core/java/android/util/MergedConfiguration.java b/core/java/android/util/MergedConfiguration.java
index 3ac44aa..4328e08 100644
--- a/core/java/android/util/MergedConfiguration.java
+++ b/core/java/android/util/MergedConfiguration.java
@@ -33,9 +33,9 @@
  */
 public class MergedConfiguration implements Parcelable {
 
-    private Configuration mGlobalConfig = new Configuration();
-    private Configuration mOverrideConfig = new Configuration();
-    private Configuration mMergedConfig = new Configuration();
+    private final Configuration mGlobalConfig = new Configuration();
+    private final Configuration mOverrideConfig = new Configuration();
+    private final Configuration mMergedConfig = new Configuration();
 
     public MergedConfiguration() {
     }
@@ -59,15 +59,15 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeParcelable(mGlobalConfig, flags);
-        dest.writeParcelable(mOverrideConfig, flags);
-        dest.writeParcelable(mMergedConfig, flags);
+        mGlobalConfig.writeToParcel(dest, flags);
+        mOverrideConfig.writeToParcel(dest, flags);
+        mMergedConfig.writeToParcel(dest, flags);
     }
 
     public void readFromParcel(Parcel source) {
-        mGlobalConfig = source.readParcelable(Configuration.class.getClassLoader());
-        mOverrideConfig = source.readParcelable(Configuration.class.getClassLoader());
-        mMergedConfig = source.readParcelable(Configuration.class.getClassLoader());
+        mGlobalConfig.readFromParcel(source);
+        mOverrideConfig.readFromParcel(source);
+        mMergedConfig.readFromParcel(source);
     }
 
     @Override
diff --git a/core/java/android/util/OWNERS b/core/java/android/util/OWNERS
index 14aa386..5425c21 100644
--- a/core/java/android/util/OWNERS
+++ b/core/java/android/util/OWNERS
@@ -2,5 +2,7 @@
 per-file FeatureFlagUtils.java = tmfang@google.com
 per-file FeatureFlagUtils.java = asapperstein@google.com
 
-per-file TypedValue.java = file:/core/java/android/content/res/OWNERS
 per-file AttributeSet.java = file:/core/java/android/content/res/OWNERS
+per-file TypedValue.java = file:/core/java/android/content/res/OWNERS
+
+per-file PackageUtils.java = file:/core/java/android/content/pm/OWNERS
diff --git a/core/java/android/util/RotationUtils.java b/core/java/android/util/RotationUtils.java
index 698cb77..0ac2c9c 100644
--- a/core/java/android/util/RotationUtils.java
+++ b/core/java/android/util/RotationUtils.java
@@ -24,6 +24,7 @@
 import android.annotation.Dimension;
 import android.graphics.Insets;
 import android.graphics.Matrix;
+import android.graphics.Rect;
 import android.view.Surface.Rotation;
 
 /**
@@ -73,6 +74,60 @@
     }
 
     /**
+     * Rotates bounds as if parentBounds and bounds are a group. The group is rotated from
+     * oldRotation to newRotation. This assumes that parentBounds is at 0,0 and remains at 0,0 after
+     * rotation. The bounds will be at the same physical position in parentBounds.
+     *
+     * Only 'inOutBounds' is mutated.
+     */
+    public static void rotateBounds(Rect inOutBounds, Rect parentBounds, @Rotation int oldRotation,
+            @Rotation int newRotation) {
+        rotateBounds(inOutBounds, parentBounds, deltaRotation(oldRotation, newRotation));
+    }
+
+    /**
+     * Rotates bounds as if parentBounds and bounds are a group. The group is rotated by `delta`
+     * 90-degree counter-clockwise increments. This assumes that parentBounds is at 0,0 and
+     * remains at 0,0 after rotation. The bounds will be at the same physical position in
+     * parentBounds.
+     *
+     * Only 'inOutBounds' is mutated.
+     */
+    public static void rotateBounds(Rect inOutBounds, Rect parentBounds, @Rotation int rotation) {
+        final int origLeft = inOutBounds.left;
+        final int origTop = inOutBounds.top;
+        switch (rotation) {
+            case ROTATION_0:
+                return;
+            case ROTATION_90:
+                inOutBounds.left = inOutBounds.top;
+                inOutBounds.top = parentBounds.right - inOutBounds.right;
+                inOutBounds.right = inOutBounds.bottom;
+                inOutBounds.bottom = parentBounds.right - origLeft;
+                return;
+            case ROTATION_180:
+                inOutBounds.left = parentBounds.right - inOutBounds.right;
+                inOutBounds.right = parentBounds.right - origLeft;
+                inOutBounds.top = parentBounds.bottom - inOutBounds.bottom;
+                inOutBounds.bottom = parentBounds.bottom - origTop;
+                return;
+            case ROTATION_270:
+                inOutBounds.left = parentBounds.bottom - inOutBounds.bottom;
+                inOutBounds.bottom = inOutBounds.right;
+                inOutBounds.right = parentBounds.bottom - inOutBounds.top;
+                inOutBounds.top = origLeft;
+        }
+    }
+
+    /** @return the rotation needed to rotate from oldRotation to newRotation. */
+    @Rotation
+    public static int deltaRotation(int oldRotation, int newRotation) {
+        int delta = newRotation - oldRotation;
+        if (delta < 0) delta += 4;
+        return delta;
+    }
+
+    /**
      * Sets a matrix such that given a rotation, it transforms physical display
      * coordinates to that rotation's logical coordinates.
      *
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java
index 6718e93..05c86172 100644
--- a/core/java/android/util/SparseArray.java
+++ b/core/java/android/util/SparseArray.java
@@ -510,10 +510,12 @@
     }
 
     /**
+     * Compares the contents of this {@link SparseArray} to the specified {@link SparseArray}.
+     *
      * For backwards compatibility reasons, {@link Object#equals(Object)} cannot be implemented,
      * so this serves as a manually invoked alternative.
      */
-    public boolean contentEquals(@Nullable SparseArray<E> other) {
+    public boolean contentEquals(@Nullable SparseArray<?> other) {
         if (other == null) {
             return false;
         }
@@ -534,6 +536,9 @@
     }
 
     /**
+     * Returns a hash code value for the contents of this {@link SparseArray}, combining the
+     * {@link Objects#hashCode(Object)} result of all its keys and values.
+     *
      * For backwards compatibility, {@link Object#hashCode()} cannot be implemented, so this serves
      * as a manually invoked alternative.
      */
diff --git a/core/java/android/util/apk/OWNERS b/core/java/android/util/apk/OWNERS
new file mode 100644
index 0000000..52c9550
--- /dev/null
+++ b/core/java/android/util/apk/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/content/pm/OWNERS
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 9473845..09452828 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -383,7 +383,8 @@
         final List<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList;
         infos.clear();
         try {
-            if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) {
+            if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null
+                    || viewId == null) {
                 return;
             }
             mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags;
diff --git a/core/java/android/view/AppTransitionAnimationSpec.java b/core/java/android/view/AppTransitionAnimationSpec.java
index 877bb56..3215f2b 100644
--- a/core/java/android/view/AppTransitionAnimationSpec.java
+++ b/core/java/android/view/AppTransitionAnimationSpec.java
@@ -28,8 +28,8 @@
 
     public AppTransitionAnimationSpec(Parcel in) {
         taskId = in.readInt();
-        rect = in.readParcelable(null);
-        buffer = in.readParcelable(null);
+        rect = in.readTypedObject(Rect.CREATOR);
+        buffer = in.readTypedObject(HardwareBuffer.CREATOR);
     }
 
     @Override
@@ -40,8 +40,8 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(taskId);
-        dest.writeParcelable(rect, 0 /* flags */);
-        dest.writeParcelable(buffer, 0);
+        dest.writeTypedObject(rect, 0 /* flags */);
+        dest.writeTypedObject(buffer, 0 /* flags */);
     }
 
     public static final @android.annotation.NonNull Parcelable.Creator<AppTransitionAnimationSpec> CREATOR
diff --git a/core/java/android/view/CrossWindowBlurListeners.java b/core/java/android/view/CrossWindowBlurListeners.java
new file mode 100644
index 0000000..5a1b850
--- /dev/null
+++ b/core/java/android/view/CrossWindowBlurListeners.java
@@ -0,0 +1,137 @@
+/**
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.util.function.Consumer;
+
+/**
+ * Class that holds all registered {@link CrossWindowBlurEnabledListener}s. It listens
+ * for updates from the WindowManagerService and updates all registered listeners.
+ * @hide
+ */
+public final class CrossWindowBlurListeners {
+    private static final String TAG = "CrossWindowBlurListeners";
+
+    // property for background blur support in surface flinger
+    private static final String BLUR_PROPERTY = "ro.surface_flinger.supports_background_blur";
+    public static final boolean CROSS_WINDOW_BLUR_SUPPORTED =
+            SystemProperties.get(BLUR_PROPERTY, "default").equals("1");
+
+    private static volatile CrossWindowBlurListeners sInstance;
+    private static final Object sLock = new Object();
+
+    private final BlurEnabledListenerInternal mListenerInternal = new BlurEnabledListenerInternal();
+    private final ArraySet<Consumer<Boolean>> mListeners = new ArraySet();
+    private final Handler mMainHandler = new Handler(Looper.getMainLooper());
+    private boolean mInternalListenerAttached = false;
+    private boolean mCrossWindowBlurEnabled;
+
+    private CrossWindowBlurListeners() {}
+
+    /**
+     * Returns a CrossWindowBlurListeners instance
+     */
+    public static CrossWindowBlurListeners getInstance() {
+        CrossWindowBlurListeners instance = sInstance;
+        if (instance == null) {
+
+            synchronized (sLock) {
+                instance = sInstance;
+                if (instance == null) {
+                    instance = new CrossWindowBlurListeners();
+                    sInstance = instance;
+                }
+            }
+        }
+        return instance;
+    }
+
+    boolean isCrossWindowBlurEnabled() {
+        synchronized (sLock) {
+            attachInternalListenerIfNeededLocked();
+            return mCrossWindowBlurEnabled;
+        }
+    }
+
+    void addListener(Consumer<Boolean> listener) {
+        if (listener == null) return;
+
+        synchronized (sLock) {
+            attachInternalListenerIfNeededLocked();
+
+            mListeners.add(listener);
+            notifyListenerOnMain(listener, mCrossWindowBlurEnabled);
+        }
+    }
+
+
+    void removeListener(Consumer<Boolean> listener) {
+        if (listener == null) return;
+
+        synchronized (sLock) {
+            mListeners.remove(listener);
+
+            if (mInternalListenerAttached && mListeners.size() == 0) {
+                try {
+                    WindowManagerGlobal.getWindowManagerService()
+                            .unregisterCrossWindowBlurEnabledListener(mListenerInternal);
+                    mInternalListenerAttached = false;
+                } catch (RemoteException e) {
+                    Log.d(TAG, "Could not unregister ICrossWindowBlurEnabledListener");
+                }
+            }
+        }
+    }
+
+    private void attachInternalListenerIfNeededLocked() {
+        if (!mInternalListenerAttached) {
+            try {
+                mCrossWindowBlurEnabled = WindowManagerGlobal.getWindowManagerService()
+                        .registerCrossWindowBlurEnabledListener(mListenerInternal);
+                mInternalListenerAttached = true;
+            } catch (RemoteException e) {
+                Log.d(TAG, "Could not register ICrossWindowBlurEnabledListener");
+            }
+        }
+    }
+
+    private void notifyListenerOnMain(Consumer<Boolean> listener, boolean enabled) {
+        mMainHandler.post(() -> {
+            listener.accept(enabled);
+        });
+    }
+
+    private final class BlurEnabledListenerInternal extends ICrossWindowBlurEnabledListener.Stub {
+        @Override
+        public void onCrossWindowBlurEnabledChanged(boolean enabled) {
+            synchronized (sLock) {
+                mCrossWindowBlurEnabled = enabled;
+
+                for (int i = 0; i < mListeners.size(); i++) {
+                    notifyListenerOnMain(mListeners.valueAt(i), enabled);
+                }
+            }
+        }
+    }
+}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 0ba1dfe..8117c96 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -34,6 +34,7 @@
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.hardware.display.DeviceProductInfo;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerGlobal;
 import android.os.Build;
@@ -1181,6 +1182,18 @@
     }
 
     /**
+     * Returns the product-specific information about the display or the directly connected
+     * device on the display chain.
+     * For example, if the display is transitively connected, this field may contain product
+     * information about the intermediate device.
+     * Returns {@code null} if product information is not available.
+     */
+    @Nullable
+    public DeviceProductInfo getDeviceProductInfo() {
+        return mDisplayInfo.deviceProductInfo;
+    }
+
+    /**
      * Gets display metrics that describe the size and density of this display.
      * The size returned by this method does not necessarily represent the
      * actual raw size (native resolution) of the display.
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 2a00b5a..655f423 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -810,6 +810,9 @@
         if ((flags & Display.FLAG_TRUSTED) != 0) {
             result.append(", FLAG_TRUSTED");
         }
+        if ((flags & Display.FLAG_OWN_DISPLAY_GROUP) != 0) {
+            result.append(", FLAG_OWN_DISPLAY_GROUP");
+        }
         return result.toString();
     }
 }
diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java
index 6543de1..eb49e52 100644
--- a/core/java/android/view/FrameMetrics.java
+++ b/core/java/android/view/FrameMetrics.java
@@ -213,8 +213,7 @@
             Index.FRAME_TIMELINE_VSYNC_ID,
             Index.INTENDED_VSYNC,
             Index.VSYNC,
-            Index.OLDEST_INPUT_EVENT,
-            Index.NEWEST_INPUT_EVENT,
+            Index.INPUT_EVENT_ID,
             Index.HANDLE_INPUT_START,
             Index.ANIMATION_START,
             Index.PERFORM_TRAVERSALS_START,
@@ -225,8 +224,11 @@
             Index.ISSUE_DRAW_COMMANDS_START,
             Index.SWAP_BUFFERS,
             Index.FRAME_COMPLETED,
+            Index.DEQUEUE_BUFFER_DURATION,
+            Index.QUEUE_BUFFER_DURATION,
             Index.GPU_COMPLETED,
-            Index.SWAP_BUFFERS_COMPLETED
+            Index.SWAP_BUFFERS_COMPLETED,
+            Index.DISPLAY_PRESENT_TIME,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Index {
@@ -234,20 +236,22 @@
         int FRAME_TIMELINE_VSYNC_ID = 1;
         int INTENDED_VSYNC = 2;
         int VSYNC = 3;
-        int OLDEST_INPUT_EVENT = 4;
-        int NEWEST_INPUT_EVENT = 5;
-        int HANDLE_INPUT_START = 6;
-        int ANIMATION_START = 7;
-        int PERFORM_TRAVERSALS_START = 8;
-        int DRAW_START = 9;
-        int FRAME_DEADLINE = 10;
-        int SYNC_QUEUED = 11;
-        int SYNC_START = 12;
-        int ISSUE_DRAW_COMMANDS_START = 13;
-        int SWAP_BUFFERS = 14;
-        int FRAME_COMPLETED = 15;
-        int GPU_COMPLETED = 18;
-        int SWAP_BUFFERS_COMPLETED = 19;
+        int INPUT_EVENT_ID = 4;
+        int HANDLE_INPUT_START = 5;
+        int ANIMATION_START = 6;
+        int PERFORM_TRAVERSALS_START = 7;
+        int DRAW_START = 8;
+        int FRAME_DEADLINE = 9;
+        int SYNC_QUEUED = 10;
+        int SYNC_START = 11;
+        int ISSUE_DRAW_COMMANDS_START = 12;
+        int SWAP_BUFFERS = 13;
+        int FRAME_COMPLETED = 14;
+        int DEQUEUE_BUFFER_DURATION = 15;
+        int QUEUE_BUFFER_DURATION = 16;
+        int GPU_COMPLETED = 17;
+        int SWAP_BUFFERS_COMPLETED = 18;
+        int DISPLAY_PRESENT_TIME = 19;
 
         int FRAME_STATS_COUNT = 20; // must always be last and in sync with
                                     // FrameInfoIndex::NumIndexes in libs/hwui/FrameInfo.h
diff --git a/core/java/android/view/ICrossWindowBlurEnabledListener.aidl b/core/java/android/view/ICrossWindowBlurEnabledListener.aidl
new file mode 100644
index 0000000..69286e2
--- /dev/null
+++ b/core/java/android/view/ICrossWindowBlurEnabledListener.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.view;
+
+/**
+ * Listener to be invoked when cross-window blur is enabled or disabled.
+ * {@hide}
+ */
+oneway interface ICrossWindowBlurEnabledListener {
+    /**
+     * Method that will be invoked when cross-window blur is enabled or disabled.
+     * @param enabled True if cross-window blur is enabled.
+     */
+    void onCrossWindowBlurEnabledChanged(boolean enabled);
+}
diff --git a/core/java/android/view/IPinnedStackListener.aidl b/core/java/android/view/IPinnedTaskListener.aidl
similarity index 95%
rename from core/java/android/view/IPinnedStackListener.aidl
rename to core/java/android/view/IPinnedTaskListener.aidl
index 29c9c15..c31e67e 100644
--- a/core/java/android/view/IPinnedStackListener.aidl
+++ b/core/java/android/view/IPinnedTaskListener.aidl
@@ -23,11 +23,11 @@
 import android.view.DisplayInfo;
 
 /**
- * Listener for changes to the pinned stack made by the WindowManager.
+ * Listener for changes to the pinned task made by the WindowManager.
  *
  * @hide
  */
-oneway interface IPinnedStackListener {
+oneway interface IPinnedTaskListener {
 
     /**
      * Called when the window manager has detected a change that would cause the movement bounds
diff --git a/core/java/android/view/IScrollCaptureCallbacks.aidl b/core/java/android/view/IScrollCaptureCallbacks.aidl
index d97e3c6..26eaac0 100644
--- a/core/java/android/view/IScrollCaptureCallbacks.aidl
+++ b/core/java/android/view/IScrollCaptureCallbacks.aidl
@@ -16,12 +16,10 @@
 
 package android.view;
 
-import android.graphics.Point;
 import android.graphics.Rect;
+import android.view.ScrollCaptureResponse;
 import android.view.Surface;
 
-import android.view.IScrollCaptureConnection;
-
 /**
  * Asynchronous callback channel for responses to scroll capture requests.
  *
@@ -29,34 +27,30 @@
  */
 interface IScrollCaptureCallbacks {
     /**
-     * Scroll capture is available, and a connection has been provided.
+     * Provides the result of WindowManagerService#requestScrollCapture
      *
-     * @param connection a connection to a window process and scrollable content
-     * @param scrollAreaInWindow the location of scrolling in global (window) coordinate space
+     * @param response the response which describes the result
      */
-    oneway void onConnected(in IScrollCaptureConnection connection, in Rect scrollBounds,
-            in Point positionInWindow);
+    oneway void onScrollCaptureResponse(in ScrollCaptureResponse response);
 
     /**
-     * The window does not support scroll capture.
-     */
-    oneway void onUnavailable();
-
-    /**
-     * Called when the remote end has confirmed the request and is ready to begin providing image
-     * requests.
+     * Called in reply to IScrollCaptureConnection#startCapture, when the remote end has confirmed
+     * the request and is ready to begin capturing images.
      */
     oneway void onCaptureStarted();
 
     /**
-     * Received a response from a capture request.
+     * Received a response from a capture request. The provided rectangle indicates the portion
+     * of the requested rectangle which was captured. An empty rectangle indicates that the request
+     * could not be satisfied (most commonly due to the available scrolling range).
+     *
+     * @param flags flags describing additional status of the result
+     * @param capturedArea the actual area of the image captured
      */
-    oneway void onCaptureBufferSent(long frameNumber, in Rect capturedArea);
+    oneway void onImageRequestCompleted(int flags, in Rect capturedArea);
 
     /**
-     * Signals that the capture session has completed and the target window may be returned to
-     * normal interactive use. This may be due to normal shutdown, or after a timeout or other
-     * unrecoverable state change such as activity lifecycle, window visibility or focus.
+     * Signals that the capture session has completed and the target window is ready for normal use.
      */
-    oneway void onConnectionClosed();
+    oneway void onCaptureEnded();
 }
diff --git a/core/java/android/view/IScrollCaptureConnection.aidl b/core/java/android/view/IScrollCaptureConnection.aidl
index 63a4f48..c55e888 100644
--- a/core/java/android/view/IScrollCaptureConnection.aidl
+++ b/core/java/android/view/IScrollCaptureConnection.aidl
@@ -17,33 +17,45 @@
 package android.view;
 
 import android.graphics.Rect;
+import android.os.ICancellationSignal;
 import android.view.Surface;
 
 
  /**
-   * Interface implemented by a client of the Scroll Capture framework to receive requests
-   * to start, capture images and end the session.
+   * A remote connection to a scroll capture target.
    *
    * {@hide}
    */
 interface IScrollCaptureConnection {
 
     /**
-     * Informs the client that it has been selected for scroll capture and should prepare to
-     * to begin handling capture requests.
-     */
-    oneway void startCapture(in Surface surface);
-
-    /**
-     * Request the client capture an image within the provided rectangle.
+     * Informs the target that it has been selected for scroll capture.
      *
-     * @see android.view.ScrollCaptureCallback#onScrollCaptureRequest
+     * @param surface a return channel for image buffers
+     *
+     * @return a cancallation signal which is used cancel the request
      */
-    oneway void requestImage(in Rect captureArea);
+    ICancellationSignal startCapture(in Surface surface);
 
     /**
-     * Inform the client that capture has ended. The client should shut down and release all
-     * local resources in use and prepare for return to normal interactive usage.
+     * Request the target capture an image within the provided rectangle.
+     *
+     * @param surface a return channel for image buffers
+     * @param signal a cancallation signal which can interrupt the request
+     *
+     * @return a cancallation signal which is used cancel the request
      */
-    oneway void endCapture();
+    ICancellationSignal requestImage(in Rect captureArea);
+
+    /**
+     * Inform the target that capture has ended.
+     *
+     * @return a cancallation signal which is used cancel the request
+     */
+    ICancellationSignal endCapture();
+
+    /**
+     * Closes the connection.
+     */
+    oneway void close();
 }
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 4e4ba3f..5477800 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -35,13 +35,13 @@
 import android.view.DisplayCutout;
 import android.view.IApplicationToken;
 import android.view.IAppTransitionAnimationSpecsFuture;
-import android.view.IDockedStackListener;
+import android.view.ICrossWindowBlurEnabledListener;
 import android.view.IDisplayWindowInsetsController;
 import android.view.IDisplayWindowListener;
 import android.view.IDisplayFoldListener;
 import android.view.IDisplayWindowRotationController;
 import android.view.IOnKeyguardExitResult;
-import android.view.IPinnedStackListener;
+import android.view.IPinnedTaskListener;
 import android.view.IScrollCaptureCallbacks;
 import android.view.RemoteAnimationAdapter;
 import android.view.IRotationWatcher;
@@ -446,12 +446,12 @@
      * Sets the region the user can touch the divider. This region will be excluded from the region
      * which is used to cause a focus switch when dispatching touch.
      */
-    void setDockedStackDividerTouchRegion(in Rect touchableRegion);
+    void setDockedTaskDividerTouchRegion(in Rect touchableRegion);
 
     /**
-     * Registers a listener that will be called when the pinned stack state changes.
+     * Registers a listener that will be called when the pinned task state changes.
      */
-    void registerPinnedStackListener(int displayId, IPinnedStackListener listener);
+    void registerPinnedTaskListener(int displayId, IPinnedTaskListener listener);
 
     /**
      * Requests Keyboard Shortcuts from the displayed window.
@@ -731,7 +731,7 @@
     void showGlobalActions();
 
     /**
-     * Sets layer tracing flags for SurfaceFlingerTrace. 
+     * Sets layer tracing flags for SurfaceFlingerTrace.
      *
      * @param flags see definition in SurfaceTracing.cpp
      */
@@ -800,4 +800,20 @@
      * @param clientToken the window context's token
      */
     void unregisterWindowContextListener(IBinder clientToken);
+
+    /**
+     * Registers a listener, which is to be called whenever cross-window blur is enabled/disabled.
+     *
+     * @param listener the listener to be registered
+     * @return true if cross-window blur is currently enabled; false otherwise
+     */
+    boolean registerCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener);
+
+    /**
+     * Unregisters a listener which was registered with
+     * {@link #registerCrossWindowBlurEnabledListener()}.
+     *
+     * @param listener the listener to be unregistered
+     */
+    void unregisterCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener);
 }
diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java
index 4a5c95f..d23a1e5 100644
--- a/core/java/android/view/ImeFocusController.java
+++ b/core/java/android/view/ImeFocusController.java
@@ -116,8 +116,9 @@
         if (!hasWindowFocus || !mHasImeFocus || isInLocalFocusMode(windowAttribute)) {
             return;
         }
+        View viewForWindowFocus = focusedView != null ? focusedView : mViewRootImpl.mView;
         if (DEBUG) {
-            Log.v(TAG, "onWindowFocus: " + focusedView
+            Log.v(TAG, "onWindowFocus: " + viewForWindowFocus
                     + " softInputMode=" + InputMethodDebug.softInputModeToString(
                     windowAttribute.softInputMode));
         }
@@ -128,8 +129,8 @@
             if (DEBUG) Log.v(TAG, "Restarting due to isRestartOnNextWindowFocus as true");
             forceFocus = true;
         }
+
         // Update mNextServedView when focusedView changed.
-        final View viewForWindowFocus = focusedView != null ? focusedView : mViewRootImpl.mView;
         onViewFocusChanged(viewForWindowFocus, true);
 
         // Starting new input when the next focused view is same as served view but the currently
diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java
index 5f2bccc..e6cf683 100644
--- a/core/java/android/view/InsetsSource.java
+++ b/core/java/android/view/InsetsSource.java
@@ -261,11 +261,7 @@
 
     public InsetsSource(Parcel in) {
         mType = in.readInt();
-        if (in.readInt() != 0) {
-            mFrame = Rect.CREATOR.createFromParcel(in);
-        } else {
-            mFrame = null;
-        }
+        mFrame = Rect.CREATOR.createFromParcel(in);
         if (in.readInt() != 0) {
             mVisibleFrame = Rect.CREATOR.createFromParcel(in);
         } else {
@@ -282,12 +278,7 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mType);
-        if (mFrame != null) {
-            dest.writeInt(1);
-            mFrame.writeToParcel(dest, 0);
-        } else {
-            dest.writeInt(0);
-        }
+        mFrame.writeToParcel(dest, 0);
         if (mVisibleFrame != null) {
             dest.writeInt(1);
             mVisibleFrame.writeToParcel(dest, 0);
diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java
index c717c2a..1d4b411 100644
--- a/core/java/android/view/InsetsSourceControl.java
+++ b/core/java/android/view/InsetsSourceControl.java
@@ -77,8 +77,8 @@
 
     public InsetsSourceControl(Parcel in) {
         mType = in.readInt();
-        mLeash = in.readParcelable(null /* loader */);
-        mSurfacePosition = in.readParcelable(null /* loader */);
+        mLeash = in.readTypedObject(SurfaceControl.CREATOR);
+        mSurfacePosition = in.readTypedObject(Point.CREATOR);
         mSkipAnimationOnce = in.readBoolean();
     }
 
@@ -119,8 +119,8 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mType);
-        dest.writeParcelable(mLeash, 0 /* flags*/);
-        dest.writeParcelable(mSurfacePosition, 0 /* flags*/);
+        dest.writeTypedObject(mLeash, 0 /* parcelableFlags */);
+        dest.writeTypedObject(mSurfacePosition, 0 /* parcelableFlags */);
         dest.writeBoolean(mSkipAnimationOnce);
     }
 
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 21dd1fb..fce1952 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -156,7 +156,7 @@
     static final int ISIDE_FLOATING = 4;
     static final int ISIDE_UNKNOWN = 5;
 
-    private InsetsSource[] mSources = new InsetsSource[SIZE];
+    private final InsetsSource[] mSources = new InsetsSource[SIZE];
 
     /**
      * The frame of the display these sources are relative to.
@@ -804,7 +804,7 @@
     public void writeToParcel(Parcel dest, int flags) {
         mDisplayFrame.writeToParcel(dest, flags);
         mDisplayCutout.writeToParcel(dest, flags);
-        dest.writeParcelableArray(mSources, 0);
+        dest.writeTypedArray(mSources, 0 /* parcelableFlags */);
         dest.writeTypedObject(mRoundedCorners, flags);
     }
 
@@ -820,9 +820,9 @@
     };
 
     public void readFromParcel(Parcel in) {
-        mDisplayFrame.set(Rect.CREATOR.createFromParcel(in));
-        mDisplayCutout.set(DisplayCutout.ParcelableWrapper.CREATOR.createFromParcel(in));
-        mSources = in.readParcelableArray(null, InsetsSource.class);
+        mDisplayFrame.readFromParcel(in);
+        mDisplayCutout.readFromParcel(in);
+        in.readTypedArray(mSources, InsetsSource.CREATOR);
         mRoundedCorners = in.readTypedObject(RoundedCorners.CREATOR);
     }
 
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 5ce4c50..6c8753b 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -27,7 +27,7 @@
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.util.AttributeSet;
-import android.widget.FrameLayout;
+import android.widget.RelativeLayout;
 import android.widget.RemoteViews;
 
 import com.android.internal.R;
@@ -42,7 +42,7 @@
  * @hide
  */
 @RemoteViews.RemoteView
-public class NotificationHeaderView extends FrameLayout {
+public class NotificationHeaderView extends RelativeLayout {
     private final int mHeadingEndMargin;
     private final int mTouchableHeight;
     private OnClickListener mExpandClickListener;
@@ -159,7 +159,7 @@
      * @param extraMarginEnd extra margin in px
      */
     public void setTopLineExtraMarginEnd(int extraMarginEnd) {
-        mTopLineView.setHeaderTextMarginEnd(extraMarginEnd + mHeadingEndMargin);
+        mTopLineView.setHeaderTextMarginEnd(extraMarginEnd);
     }
 
     /**
@@ -181,12 +181,15 @@
      * @return extra margin
      */
     public int getTopLineExtraMarginEnd() {
-        return mTopLineView.getHeaderTextMarginEnd() - mHeadingEndMargin;
+        return mTopLineView.getHeaderTextMarginEnd();
     }
 
     /**
      * Get the base margin at the end of the top line view.
      * Add this to {@link #getTopLineExtraMarginEnd()} to get the total margin of the top line.
+     * <p>
+     * NOTE: This method's result is only valid if the expander does not have a number. Currently
+     * only groups headers and conversations have numbers, so this is safe to use by MediaStyle.
      *
      * @return base margin
      */
diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS
index e66b17a..cbb86de 100644
--- a/core/java/android/view/OWNERS
+++ b/core/java/android/view/OWNERS
@@ -57,6 +57,7 @@
 per-file ViewRootImpl.java = file:/services/core/java/com/android/server/input/OWNERS
 per-file ViewRootImpl.java = file:/services/core/java/com/android/server/wm/OWNERS
 per-file ViewRootImpl.java = file:/core/java/android/view/inputmethod/OWNERS
+per-file AccessibilityInteractionController.java = file:/services/accessibility/OWNERS
 
 # WindowManager
 per-file DisplayCutout.aidl = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/java/android/view/RemoteAnimationDefinition.java b/core/java/android/view/RemoteAnimationDefinition.java
index a5ff19e..ea97995 100644
--- a/core/java/android/view/RemoteAnimationDefinition.java
+++ b/core/java/android/view/RemoteAnimationDefinition.java
@@ -184,13 +184,13 @@
         }
 
         private RemoteAnimationAdapterEntry(Parcel in) {
-            adapter = in.readParcelable(RemoteAnimationAdapter.class.getClassLoader());
+            adapter = in.readTypedObject(RemoteAnimationAdapter.CREATOR);
             activityTypeFilter = in.readInt();
         }
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeParcelable(adapter, flags);
+            dest.writeTypedObject(adapter, flags);
             dest.writeInt(activityTypeFilter);
         }
 
diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java
index 258a72c..b1b670f 100644
--- a/core/java/android/view/RemoteAnimationTarget.java
+++ b/core/java/android/view/RemoteAnimationTarget.java
@@ -222,20 +222,20 @@
     public RemoteAnimationTarget(Parcel in) {
         taskId = in.readInt();
         mode = in.readInt();
-        leash = in.readParcelable(null);
+        leash = in.readTypedObject(SurfaceControl.CREATOR);
         isTranslucent = in.readBoolean();
-        clipRect = in.readParcelable(null);
-        contentInsets = in.readParcelable(null);
+        clipRect = in.readTypedObject(Rect.CREATOR);
+        contentInsets = in.readTypedObject(Rect.CREATOR);
         prefixOrderIndex = in.readInt();
-        position = in.readParcelable(null);
-        localBounds = in.readParcelable(null);
-        sourceContainerBounds = in.readParcelable(null);
-        screenSpaceBounds = in.readParcelable(null);
-        windowConfiguration = in.readParcelable(null);
+        position = in.readTypedObject(Point.CREATOR);
+        localBounds = in.readTypedObject(Rect.CREATOR);
+        sourceContainerBounds = in.readTypedObject(Rect.CREATOR);
+        screenSpaceBounds = in.readTypedObject(Rect.CREATOR);
+        windowConfiguration = in.readTypedObject(WindowConfiguration.CREATOR);
         isNotInRecents = in.readBoolean();
-        startLeash = in.readParcelable(null);
-        startBounds = in.readParcelable(null);
-        pictureInPictureParams = in.readParcelable(null);
+        startLeash = in.readTypedObject(SurfaceControl.CREATOR);
+        startBounds = in.readTypedObject(Rect.CREATOR);
+        pictureInPictureParams = in.readTypedObject(PictureInPictureParams.CREATOR);
     }
 
     @Override
@@ -247,20 +247,20 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(taskId);
         dest.writeInt(mode);
-        dest.writeParcelable(leash, 0 /* flags */);
+        dest.writeTypedObject(leash, 0 /* flags */);
         dest.writeBoolean(isTranslucent);
-        dest.writeParcelable(clipRect, 0 /* flags */);
-        dest.writeParcelable(contentInsets, 0 /* flags */);
+        dest.writeTypedObject(clipRect, 0 /* flags */);
+        dest.writeTypedObject(contentInsets, 0 /* flags */);
         dest.writeInt(prefixOrderIndex);
-        dest.writeParcelable(position, 0 /* flags */);
-        dest.writeParcelable(localBounds, 0 /* flags */);
-        dest.writeParcelable(sourceContainerBounds, 0 /* flags */);
-        dest.writeParcelable(screenSpaceBounds, 0 /* flags */);
-        dest.writeParcelable(windowConfiguration, 0 /* flags */);
+        dest.writeTypedObject(position, 0 /* flags */);
+        dest.writeTypedObject(localBounds, 0 /* flags */);
+        dest.writeTypedObject(sourceContainerBounds, 0 /* flags */);
+        dest.writeTypedObject(screenSpaceBounds, 0 /* flags */);
+        dest.writeTypedObject(windowConfiguration, 0 /* flags */);
         dest.writeBoolean(isNotInRecents);
-        dest.writeParcelable(startLeash, 0 /* flags */);
-        dest.writeParcelable(startBounds, 0 /* flags */);
-        dest.writeParcelable(pictureInPictureParams, 0 /* flags */);
+        dest.writeTypedObject(startLeash, 0 /* flags */);
+        dest.writeTypedObject(startBounds, 0 /* flags */);
+        dest.writeTypedObject(pictureInPictureParams, 0 /* flags */);
     }
 
     public void dump(PrintWriter pw, String prefix) {
diff --git a/core/java/android/view/ScrollCaptureCallback.java b/core/java/android/view/ScrollCaptureCallback.java
index d3aad2c..1688616 100644
--- a/core/java/android/view/ScrollCaptureCallback.java
+++ b/core/java/android/view/ScrollCaptureCallback.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.UiThread;
 import android.graphics.Rect;
+import android.os.CancellationSignal;
 
 import java.util.function.Consumer;
 
@@ -58,8 +59,6 @@
  * @see View#setScrollCaptureHint(int)
  * @see View#setScrollCaptureCallback(ScrollCaptureCallback)
  * @see Window#registerScrollCaptureCallback(ScrollCaptureCallback)
- *
- * @hide
  */
 @UiThread
 public interface ScrollCaptureCallback {
@@ -68,80 +67,84 @@
      * The system is searching for the appropriate scrolling container to capture and would like to
      * know the size and position of scrolling content handled by this callback.
      * <p>
-     * Implementations should inset {@code containingViewBounds} to cover only the area within the
-     * containing view where scrolling content may be positioned. This should cover only the content
-     * which tracks with scrolling movement.
+     * To determine scroll bounds, an implementation should inset the visible bounds of the
+     * containing view to cover only the area where scrolling content may be positioned. This
+     * should cover only the content which tracks with scrolling movement.
      * <p>
-     * Return the updated rectangle to {@code resultConsumer}. If for any reason the scrolling
-     * content is not available to capture, a {@code null} rectangle may be returned, and this view
-     * will be excluded as the target for this request.
+     * Return the updated rectangle to {@link Consumer#accept onReady.accept}. If for any reason the
+     * scrolling content is not available to capture, a empty rectangle may be returned which will
+     * exclude this view from consideration.
      * <p>
-     * Responses received after XXXms will be discarded.
-     * <p>
-     * TODO: finalize timeout
+     * This request may be cancelled via the provided {@link CancellationSignal}. When this happens,
+     * any future call to {@link Consumer#accept onReady.accept} will have no effect and this
+     * content will be omitted from the search results.
      *
-     * @param onReady              consumer for the updated rectangle
+     * @param signal  signal to cancel the operation in progress
+     * @param onReady consumer for the updated rectangle
      */
-    void onScrollCaptureSearch(@NonNull Consumer<Rect> onReady);
+    void onScrollCaptureSearch(@NonNull CancellationSignal signal, @NonNull Consumer<Rect> onReady);
 
     /**
      * Scroll Capture has selected this callback to provide the scrolling image content.
      * <p>
-     * The onReady signal should be called when ready to begin handling image requests.
+     * {@link Runnable#run onReady.run} should be called when ready to begin handling image
+     * requests.
+     * <p>
+     * This request may be cancelled via the provided {@link CancellationSignal}. When this happens,
+     * any future call to {@link Runnable#run onReady.run} will have no effect and provided session
+     * will not be activated.
+     *
+     * @param session the current session, resources provided by it are valid for use until the
+     *                {@link #onScrollCaptureEnd(Runnable) session ends}
+     * @param signal  signal to cancel the operation in progress
+     * @param onReady signal used to report completion of the request
      */
-    void onScrollCaptureStart(@NonNull ScrollCaptureSession session, @NonNull Runnable onReady);
+    void onScrollCaptureStart(@NonNull ScrollCaptureSession session,
+            @NonNull CancellationSignal signal, @NonNull Runnable onReady);
 
     /**
      * An image capture has been requested from the scrolling content.
      * <p>
-     * <code>captureArea</code> contains the bounds of the image requested, relative to the
-     * rectangle provided by {@link ScrollCaptureCallback#onScrollCaptureSearch}, referred to as
-     * {@code scrollBounds}.
-     * here.
+     * The requested rectangle describes an area inside the target view, relative to
+     * <code>scrollBounds</code>. The content may be offscreen, above or below the current visible
+     * portion of the target view. To handle the request, render the available portion of this
+     * rectangle to a buffer and return it via the Surface available from {@link
+     * ScrollCaptureSession#getSurface()}.
      * <p>
-     * A series of requests will step by a constant vertical amount relative to {@code
-     * scrollBounds}, moving through the scrolling range of content, above and below the current
-     * visible area. The rectangle's vertical position will not account for any scrolling movement
-     * since capture started. Implementations therefore must track any scroll position changes and
-     * subtract this distance from requests.
+     * Note: Implementations are only required to render the requested content, and may do so into
+     * off-screen buffers without scrolling if they are able.
      * <p>
-     * To handle a request, the content should be scrolled to maximize the visible area of the
-     * requested rectangle. Offset {@code captureArea} again to account for any further scrolling.
+     * The resulting available portion of the request must be computed as a portion of {@code
+     * captureArea}, and sent to signal the operation is complete, using  {@link Consumer#accept
+     * onComplete.accept}. If the requested rectangle is  partially or fully out of bounds the
+     * resulting portion should be returned. If no portion is available (outside of available
+     * content), then skip sending any buffer and report an empty Rect as result.
      * <p>
-     * Finally, clip this rectangle against scrollBounds to determine what portion, if any is
-     * visible content to capture. If the rectangle is completely clipped, set it to {@link
-     * Rect#setEmpty() empty} and skip the next step.
-     * <p>
-     * Make a copy of {@code captureArea}, transform to window coordinates and draw the window,
-     * clipped to this rectangle, into the {@link ScrollCaptureSession#getSurface() surface} at
-     * offset (0,0).
-     * <p>
-     * Finally, return the resulting {@code captureArea} using
-     * {@link ScrollCaptureSession#notifyBufferSent}.
-     * <p>
-     * If the response is not supplied within XXXms, the session will end with a call to {@link
-     * #onScrollCaptureEnd}, after which {@code session} is invalid and should be discarded.
-     * <p>
-     * TODO: finalize timeout
-     * <p>
+     * This request may be cancelled via the provided {@link CancellationSignal}. When this happens,
+     * any future call to {@link Consumer#accept onComplete.accept} will be ignored until the next
+     * request.
      *
+     * @param session the current session, resources provided by it are valid for use until the
+     *                {@link #onScrollCaptureEnd(Runnable) session ends}
+     * @param signal      signal to cancel the operation in progress
      * @param captureArea the area to capture, a rectangle within {@code scrollBounds}
+     * @param onComplete  a consumer for the captured area
      */
-    void onScrollCaptureImageRequest(
-            @NonNull ScrollCaptureSession session, @NonNull Rect captureArea);
+    void onScrollCaptureImageRequest(@NonNull ScrollCaptureSession session,
+            @NonNull CancellationSignal signal, @NonNull Rect captureArea,
+            @NonNull Consumer<Rect> onComplete);
 
     /**
      * Signals that capture has ended. Implementations should release any temporary resources or
      * references to objects in use during the capture. Any resources obtained from the session are
      * now invalid and attempts to use them after this point may throw an exception.
      * <p>
-     * The window should be returned as much as possible to its original state when capture started.
-     * At a minimum, the content should be scrolled to its original position.
+     * The window should be returned to its original state when capture started. At a minimum, the
+     * content should be scrolled to its original position.
      * <p>
-     * <code>onReady</code> should be called when the window should be made visible and
-     * interactive. The system will wait up to XXXms for this call before proceeding.
-     * <p>
-     * TODO: finalize timeout
+     * {@link Runnable#run onReady.run} should be called as soon as possible after the window is
+     * ready for normal interactive use. After the callback (or after a timeout, if not called) the
+     * screenshot tool will be dismissed and the window may become visible to the user at any time.
      *
      * @param onReady a callback to inform the system that the application has completed any
      *                cleanup and is ready to become visible
diff --git a/core/java/android/view/ScrollCaptureConnection.java b/core/java/android/view/ScrollCaptureConnection.java
index 0e6cdd1d..3456e01 100644
--- a/core/java/android/view/ScrollCaptureConnection.java
+++ b/core/java/android/view/ScrollCaptureConnection.java
@@ -18,18 +18,23 @@
 
 import static java.util.Objects.requireNonNull;
 
+import android.annotation.BinderThread;
 import android.annotation.NonNull;
 import android.annotation.UiThread;
-import android.annotation.WorkerThread;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.os.Handler;
+import android.os.CancellationSignal;
+import android.os.ICancellationSignal;
 import android.os.RemoteException;
+import android.os.Trace;
 import android.util.CloseGuard;
+import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.lang.ref.WeakReference;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 /**
  * Mediator between a selected scroll capture target view and a remote process.
@@ -41,270 +46,276 @@
 public class ScrollCaptureConnection extends IScrollCaptureConnection.Stub {
 
     private static final String TAG = "ScrollCaptureConnection";
-    private static final int DEFAULT_TIMEOUT = 1000;
 
-    private final Handler mHandler;
-    private ScrollCaptureTarget mSelectedTarget;
-    private int mTimeoutMillis = DEFAULT_TIMEOUT;
-
-    protected Surface mSurface;
-    private IScrollCaptureCallbacks mCallbacks;
-
+    private final Object mLock = new Object();
     private final Rect mScrollBounds;
     private final Point mPositionInWindow;
     private final CloseGuard mCloseGuard;
+    private final Executor mUiThread;
 
-    // The current session instance in use by the callback.
+    private ScrollCaptureCallback mLocal;
+    private IScrollCaptureCallbacks mRemote;
+
     private ScrollCaptureSession mSession;
 
-    // Helps manage timeout callbacks registered to handler and aids testing.
-    private DelayedAction mTimeoutAction;
+    private CancellationSignal mCancellation;
+
+    private volatile boolean mStarted;
+    private volatile boolean mConnected;
 
     /**
      * Constructs a ScrollCaptureConnection.
      *
      * @param selectedTarget  the target the client is controlling
-     * @param callbacks the callbacks to reply to system requests
+     * @param remote the callbacks to reply to system requests
      *
      * @hide
      */
     public ScrollCaptureConnection(
+            @NonNull Executor uiThread,
             @NonNull ScrollCaptureTarget selectedTarget,
-            @NonNull IScrollCaptureCallbacks callbacks) {
+            @NonNull IScrollCaptureCallbacks remote) {
+        mUiThread = requireNonNull(uiThread, "<uiThread> must non-null");
         requireNonNull(selectedTarget, "<selectedTarget> must non-null");
-        requireNonNull(callbacks, "<callbacks> must non-null");
-        final Rect scrollBounds = requireNonNull(selectedTarget.getScrollBounds(),
+        mRemote = requireNonNull(remote, "<callbacks> must non-null");
+        mScrollBounds = requireNonNull(Rect.copyOrNull(selectedTarget.getScrollBounds()),
                 "target.getScrollBounds() must be non-null to construct a client");
 
-        mSelectedTarget = selectedTarget;
-        mHandler = selectedTarget.getContainingView().getHandler();
-        mScrollBounds = new Rect(scrollBounds);
+        mLocal = selectedTarget.getCallback();
         mPositionInWindow = new Point(selectedTarget.getPositionInWindow());
 
-        mCallbacks = callbacks;
         mCloseGuard = new CloseGuard();
         mCloseGuard.open("close");
-
-        selectedTarget.getContainingView().addOnAttachStateChangeListener(
-                new View.OnAttachStateChangeListener() {
-                    @Override
-                    public void onViewAttachedToWindow(View v) {
-
-                    }
-
-                    @Override
-                    public void onViewDetachedFromWindow(View v) {
-                        selectedTarget.getContainingView().removeOnAttachStateChangeListener(this);
-                        endCapture();
-                    }
-                });
+        mConnected = true;
     }
 
-    @VisibleForTesting
-    public void setTimeoutMillis(int timeoutMillis) {
-        mTimeoutMillis = timeoutMillis;
-    }
-
-    @VisibleForTesting
-    public DelayedAction getTimeoutAction() {
-        return mTimeoutAction;
-    }
-
-    private void checkConnected() {
-        if (mSelectedTarget == null || mCallbacks == null) {
-            throw new IllegalStateException("This client has been disconnected.");
-        }
-    }
-
-    private void checkStarted() {
-        if (mSession == null) {
-            throw new IllegalStateException("Capture session has not been started!");
-        }
-    }
-
-    @WorkerThread // IScrollCaptureConnection
+    @BinderThread
     @Override
-    public void startCapture(Surface surface) throws RemoteException {
+    public ICancellationSignal startCapture(Surface surface) throws RemoteException {
         checkConnected();
-        mSurface = surface;
-        scheduleTimeout(mTimeoutMillis, this::onStartCaptureTimeout);
-        mSession = new ScrollCaptureSession(mSurface, mScrollBounds, mPositionInWindow, this);
-        mHandler.post(() -> mSelectedTarget.getCallback().onScrollCaptureStart(mSession,
-                this::onStartCaptureCompleted));
+        if (!surface.isValid()) {
+            throw new RemoteException(new IllegalArgumentException("surface must be valid"));
+        }
+
+        ICancellationSignal cancellation = CancellationSignal.createTransport();
+        mCancellation = CancellationSignal.fromTransport(cancellation);
+        mSession = new ScrollCaptureSession(surface, mScrollBounds, mPositionInWindow);
+
+        Runnable listener =
+                SafeCallback.create(mCancellation, mUiThread, this::onStartCaptureCompleted);
+        // -> UiThread
+        mUiThread.execute(() -> mLocal.onScrollCaptureStart(mSession, mCancellation, listener));
+        return cancellation;
     }
 
     @UiThread
     private void onStartCaptureCompleted() {
-        if (cancelTimeout()) {
-            mHandler.post(() -> {
-                try {
-                    mCallbacks.onCaptureStarted();
-                } catch (RemoteException e) {
-                    doShutdown();
-                }
-            });
+        mStarted = true;
+        try {
+            mRemote.onCaptureStarted();
+        } catch (RemoteException e) {
+            Log.w(TAG, "Shutting down due to error: ", e);
+            close();
         }
     }
 
-    @UiThread
-    private void onStartCaptureTimeout() {
-        endCapture();
-    }
 
-    @WorkerThread // IScrollCaptureConnection
+    @BinderThread
     @Override
-    public void requestImage(Rect requestRect) {
+    public ICancellationSignal requestImage(Rect requestRect) throws RemoteException {
+        Trace.beginSection("requestImage");
         checkConnected();
         checkStarted();
-        scheduleTimeout(mTimeoutMillis, this::onRequestImageTimeout);
-        // Response is dispatched via ScrollCaptureSession, to onRequestImageCompleted
-        mHandler.post(() -> mSelectedTarget.getCallback().onScrollCaptureImageRequest(
-                mSession, new Rect(requestRect)));
+
+        ICancellationSignal cancellation = CancellationSignal.createTransport();
+        mCancellation = CancellationSignal.fromTransport(cancellation);
+
+        Consumer<Rect> listener =
+                SafeCallback.create(mCancellation, mUiThread, this::onImageRequestCompleted);
+        // -> UiThread
+        mUiThread.execute(() -> mLocal.onScrollCaptureImageRequest(
+                mSession, mCancellation, new Rect(requestRect), listener));
+        Trace.endSection();
+        return cancellation;
     }
 
     @UiThread
-    void onRequestImageCompleted(long frameNumber, Rect capturedArea) {
-        final Rect finalCapturedArea = new Rect(capturedArea);
-        if (cancelTimeout()) {
-            mHandler.post(() -> {
-                try {
-                    mCallbacks.onCaptureBufferSent(frameNumber, finalCapturedArea);
-                } catch (RemoteException e) {
-                    doShutdown();
-                }
-            });
-        }
-    }
-
-    @UiThread
-    private void onRequestImageTimeout() {
-        endCapture();
-    }
-
-    @WorkerThread // IScrollCaptureConnection
-    @Override
-    public void endCapture() {
-        if (isStarted()) {
-            scheduleTimeout(mTimeoutMillis, this::onEndCaptureTimeout);
-            mHandler.post(() ->
-                    mSelectedTarget.getCallback().onScrollCaptureEnd(this::onEndCaptureCompleted));
-        } else {
-            disconnect();
-        }
-    }
-
-    private boolean isStarted() {
-        return mCallbacks != null && mSelectedTarget != null;
-    }
-
-    @UiThread
-    private void onEndCaptureCompleted() { // onEndCaptureCompleted
-        if (cancelTimeout()) {
-            doShutdown();
-        }
-    }
-
-    @UiThread
-    private void onEndCaptureTimeout() {
-        doShutdown();
-    }
-
-
-    private void doShutdown() {
+    void onImageRequestCompleted(Rect capturedArea) {
         try {
-            if (mCallbacks != null) {
-                mCallbacks.onConnectionClosed();
-            }
+            mRemote.onImageRequestCompleted(0, capturedArea);
         } catch (RemoteException e) {
-            // Ignore
-        } finally {
-            disconnect();
+            Log.w(TAG, "Shutting down due to error: ", e);
+            close();
         }
     }
 
+    @BinderThread
+    @Override
+    public ICancellationSignal endCapture() throws RemoteException {
+        checkConnected();
+        checkStarted();
+
+        ICancellationSignal cancellation = CancellationSignal.createTransport();
+        mCancellation = CancellationSignal.fromTransport(cancellation);
+
+        Runnable listener =
+                SafeCallback.create(mCancellation, mUiThread, this::onEndCaptureCompleted);
+        // -> UiThread
+        mUiThread.execute(() -> mLocal.onScrollCaptureEnd(listener));
+        return cancellation;
+    }
+
+    @UiThread
+    private void onEndCaptureCompleted() {
+        synchronized (mLock) {
+            mStarted = false;
+            try {
+                mRemote.onCaptureEnded();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Shutting down due to error: ", e);
+                close();
+            }
+        }
+    }
+
+    @BinderThread
+    @Override
+    public void close() {
+        if (mStarted) {
+            Log.w(TAG, "close(): capture is still started?! Ending now.");
+
+            // -> UiThread
+            mUiThread.execute(() -> mLocal.onScrollCaptureEnd(() -> { /* ignore */ }));
+            mStarted = false;
+        }
+        disconnect();
+    }
+
     /**
      * Shuts down this client and releases references to dependent objects. No attempt is made
      * to notify the controller, use with caution!
      */
-    public void disconnect() {
-        if (mSession != null) {
-            mSession.disconnect();
+    private void disconnect() {
+        synchronized (mLock) {
             mSession = null;
+            mConnected = false;
+            mStarted = false;
+            mRemote = null;
+            mLocal = null;
+            mCloseGuard.close();
         }
+    }
 
-        mSelectedTarget = null;
-        mCallbacks = null;
+    public boolean isConnected() {
+        return mConnected;
+    }
+
+    public boolean isStarted() {
+        return mStarted;
+    }
+
+    private synchronized void checkConnected() throws RemoteException {
+        synchronized (mLock) {
+            if (!mConnected) {
+                throw new RemoteException(new IllegalStateException("Not connected"));
+            }
+        }
+    }
+
+    private void checkStarted() throws RemoteException {
+        synchronized (mLock) {
+            if (!mStarted) {
+                throw new RemoteException(new IllegalStateException("Not started!"));
+            }
+        }
     }
 
     /** @return a string representation of the state of this client */
     public String toString() {
         return "ScrollCaptureConnection{"
+                + "connected=" + mConnected
+                + ", started=" + mStarted
                 + ", session=" + mSession
-                + ", selectedTarget=" + mSelectedTarget
-                + ", clientCallbacks=" + mCallbacks
+                + ", remote=" + mRemote
+                + ", local=" + mLocal
                 + "}";
     }
 
-    private boolean cancelTimeout() {
-        if (mTimeoutAction != null) {
-            return mTimeoutAction.cancel();
-        }
-        return false;
-    }
-
-    private void scheduleTimeout(long timeoutMillis, Runnable action) {
-        if (mTimeoutAction != null) {
-            mTimeoutAction.cancel();
-        }
-        mTimeoutAction = new DelayedAction(mHandler, timeoutMillis, action);
-    }
-
-    /** @hide */
     @VisibleForTesting
-    public static class DelayedAction {
-        private final AtomicBoolean mCompleted = new AtomicBoolean();
-        private final Object mToken = new Object();
-        private final Handler mHandler;
-        private final Runnable mAction;
+    public CancellationSignal getCancellation() {
+        return mCancellation;
+    }
 
-        @VisibleForTesting
-        public DelayedAction(Handler handler, long timeoutMillis, Runnable action) {
-            mHandler = handler;
-            mAction = action;
-            mHandler.postDelayed(this::onTimeout, mToken, timeoutMillis);
-        }
-
-        private boolean onTimeout() {
-            if (mCompleted.compareAndSet(false, true)) {
-                mAction.run();
-                return true;
+    protected void finalize() throws Throwable {
+        try {
+            if (mCloseGuard != null) {
+                mCloseGuard.warnIfOpen();
             }
-            return false;
+            close();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    private static class SafeCallback<T> {
+        private final CancellationSignal mSignal;
+        private final WeakReference<T> mTargetRef;
+        private final Executor mExecutor;
+        private boolean mExecuted;
+
+        protected SafeCallback(CancellationSignal signal, Executor executor, T target) {
+            mSignal = signal;
+            mTargetRef = new WeakReference<>(target);
+            mExecutor = executor;
         }
 
-        /**
-         * Cause the timeout action to run immediately and mark as timed out.
-         *
-         * @return true if the timeout was run, false if the timeout had already been canceled
-         */
-        @VisibleForTesting
-        public boolean timeoutNow() {
-            return onTimeout();
-        }
-
-        /**
-         * Attempt to cancel the timeout action (such as after a callback is made)
-         *
-         * @return true if the timeout was canceled and will not run, false if time has expired and
-         * the timeout action has or will run momentarily
-         */
-        public boolean cancel() {
-            if (!mCompleted.compareAndSet(false, true)) {
-                // Whoops, too late!
-                return false;
+        // Provide the target to the consumer to invoke, forward on handler thread ONCE,
+        // and only if noy cancelled, and the target is still available (not collected)
+        protected final void maybeAccept(Consumer<T> targetConsumer) {
+            if (mExecuted) {
+                return;
             }
-            mHandler.removeCallbacksAndMessages(mToken);
-            return true;
+            mExecuted = true;
+            if (mSignal.isCanceled()) {
+                return;
+            }
+            T target = mTargetRef.get();
+            if (target == null) {
+                return;
+            }
+            mExecutor.execute(() -> targetConsumer.accept(target));
+        }
+
+        static Runnable create(CancellationSignal signal, Executor executor, Runnable target) {
+            return new RunnableCallback(signal, executor, target);
+        }
+
+        static <T> Consumer<T> create(CancellationSignal signal, Executor executor,
+                Consumer<T> target) {
+            return new ConsumerCallback<T>(signal, executor, target);
+        }
+    }
+
+    private static final class RunnableCallback extends SafeCallback<Runnable> implements Runnable {
+        RunnableCallback(CancellationSignal signal, Executor executor, Runnable target) {
+            super(signal, executor, target);
+        }
+
+        @Override
+        public void run() {
+            maybeAccept(Runnable::run);
+        }
+    }
+
+    private static final class ConsumerCallback<T> extends SafeCallback<Consumer<T>>
+            implements Consumer<T> {
+        ConsumerCallback(CancellationSignal signal, Executor executor, Consumer<T> target) {
+            super(signal, executor, target);
+        }
+
+        @Override
+        public void accept(T value) {
+            maybeAccept((target) -> target.accept(value));
         }
     }
 }
diff --git a/core/java/android/view/ScrollCaptureResponse.aidl b/core/java/android/view/ScrollCaptureResponse.aidl
new file mode 100644
index 0000000..3de2b80
--- /dev/null
+++ b/core/java/android/view/ScrollCaptureResponse.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+parcelable ScrollCaptureResponse;
diff --git a/core/java/android/view/ScrollCaptureResponse.java b/core/java/android/view/ScrollCaptureResponse.java
new file mode 100644
index 0000000..564113e
--- /dev/null
+++ b/core/java/android/view/ScrollCaptureResponse.java
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Rect;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+import java.util.ArrayList;
+
+/** @hide */
+@DataClass(genToString = true, genGetters = true)
+public class ScrollCaptureResponse implements Parcelable {
+
+    /** Developer-facing human readable description of the result. */
+    @NonNull
+    private String mDescription = "";
+
+    // Remaining fields are non-null when isConnected() == true
+
+    /** The active connection for a successful result. */
+    @Nullable
+    @DataClass.MaySetToNull
+    private IScrollCaptureConnection mConnection = null;
+
+    /** The bounds of the window within the display */
+    @Nullable
+    private Rect mWindowBounds = null;
+
+    /** The bounds of the scrolling content, in window space. */
+    @Nullable
+    private Rect mBoundsInWindow = null;
+
+    /** The current window title. */
+    @Nullable
+    private String mWindowTitle = null;
+
+    /** Carries additional logging and debugging information when enabled. */
+    @NonNull
+    @DataClass.PluralOf("message")
+    private ArrayList<String> mMessages = new ArrayList<>();
+
+    /** Whether a connection has been returned. */
+    public boolean isConnected() {
+        return mConnection != null;
+    }
+
+
+
+
+    // Code below generated by codegen v1.0.22.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/ScrollCaptureResponse.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    @DataClass.Generated.Member
+    /* package-private */ ScrollCaptureResponse(
+            @NonNull String description,
+            @Nullable IScrollCaptureConnection connection,
+            @Nullable Rect windowBounds,
+            @Nullable Rect boundsInWindow,
+            @Nullable String windowTitle,
+            @NonNull ArrayList<String> messages) {
+        this.mDescription = description;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mDescription);
+        this.mConnection = connection;
+        this.mWindowBounds = windowBounds;
+        this.mBoundsInWindow = boundsInWindow;
+        this.mWindowTitle = windowTitle;
+        this.mMessages = messages;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mMessages);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * Developer-facing human readable description of the result.
+     */
+    @DataClass.Generated.Member
+    public @NonNull String getDescription() {
+        return mDescription;
+    }
+
+    /**
+     * The active connection for a successful result.
+     */
+    @DataClass.Generated.Member
+    public @Nullable IScrollCaptureConnection getConnection() {
+        return mConnection;
+    }
+
+    /**
+     * The bounds of the window within the display
+     */
+    @DataClass.Generated.Member
+    public @Nullable Rect getWindowBounds() {
+        return mWindowBounds;
+    }
+
+    /**
+     * The bounds of the scrolling content, in window space.
+     */
+    @DataClass.Generated.Member
+    public @Nullable Rect getBoundsInWindow() {
+        return mBoundsInWindow;
+    }
+
+    /**
+     * The current window title.
+     */
+    @DataClass.Generated.Member
+    public @Nullable String getWindowTitle() {
+        return mWindowTitle;
+    }
+
+    /**
+     * Carries additional logging and debugging information when enabled.
+     */
+    @DataClass.Generated.Member
+    public @NonNull ArrayList<String> getMessages() {
+        return mMessages;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "ScrollCaptureResponse { " +
+                "description = " + mDescription + ", " +
+                "connection = " + mConnection + ", " +
+                "windowBounds = " + mWindowBounds + ", " +
+                "boundsInWindow = " + mBoundsInWindow + ", " +
+                "windowTitle = " + mWindowTitle + ", " +
+                "messages = " + mMessages +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        byte flg = 0;
+        if (mConnection != null) flg |= 0x2;
+        if (mWindowBounds != null) flg |= 0x4;
+        if (mBoundsInWindow != null) flg |= 0x8;
+        if (mWindowTitle != null) flg |= 0x10;
+        dest.writeByte(flg);
+        dest.writeString(mDescription);
+        if (mConnection != null) dest.writeStrongInterface(mConnection);
+        if (mWindowBounds != null) dest.writeTypedObject(mWindowBounds, flags);
+        if (mBoundsInWindow != null) dest.writeTypedObject(mBoundsInWindow, flags);
+        if (mWindowTitle != null) dest.writeString(mWindowTitle);
+        dest.writeStringList(mMessages);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    protected ScrollCaptureResponse(@NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte flg = in.readByte();
+        String description = in.readString();
+        IScrollCaptureConnection connection = (flg & 0x2) == 0 ? null : IScrollCaptureConnection.Stub.asInterface(in.readStrongBinder());
+        Rect windowBounds = (flg & 0x4) == 0 ? null : (Rect) in.readTypedObject(Rect.CREATOR);
+        Rect boundsInWindow = (flg & 0x8) == 0 ? null : (Rect) in.readTypedObject(Rect.CREATOR);
+        String windowTitle = (flg & 0x10) == 0 ? null : in.readString();
+        ArrayList<String> messages = new ArrayList<>();
+        in.readStringList(messages);
+
+        this.mDescription = description;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mDescription);
+        this.mConnection = connection;
+        this.mWindowBounds = windowBounds;
+        this.mBoundsInWindow = boundsInWindow;
+        this.mWindowTitle = windowTitle;
+        this.mMessages = messages;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mMessages);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<ScrollCaptureResponse> CREATOR
+            = new Parcelable.Creator<ScrollCaptureResponse>() {
+        @Override
+        public ScrollCaptureResponse[] newArray(int size) {
+            return new ScrollCaptureResponse[size];
+        }
+
+        @Override
+        public ScrollCaptureResponse createFromParcel(@NonNull android.os.Parcel in) {
+            return new ScrollCaptureResponse(in);
+        }
+    };
+
+    /**
+     * A builder for {@link ScrollCaptureResponse}
+     */
+    @SuppressWarnings("WeakerAccess")
+    @DataClass.Generated.Member
+    public static class Builder {
+
+        private @NonNull String mDescription;
+        private @Nullable IScrollCaptureConnection mConnection;
+        private @Nullable Rect mWindowBounds;
+        private @Nullable Rect mBoundsInWindow;
+        private @Nullable String mWindowTitle;
+        private @NonNull ArrayList<String> mMessages;
+
+        private long mBuilderFieldsSet = 0L;
+
+        public Builder() {
+        }
+
+        /**
+         * Developer-facing human readable description of the result.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setDescription(@NonNull String value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x1;
+            mDescription = value;
+            return this;
+        }
+
+        /**
+         * The active connection for a successful result.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setConnection(@Nullable IScrollCaptureConnection value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2;
+            mConnection = value;
+            return this;
+        }
+
+        /**
+         * The bounds of the window within the display
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setWindowBounds(@NonNull Rect value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4;
+            mWindowBounds = value;
+            return this;
+        }
+
+        /**
+         * The bounds of the scrolling content, in window space.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setBoundsInWindow(@NonNull Rect value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x8;
+            mBoundsInWindow = value;
+            return this;
+        }
+
+        /**
+         * The current window title.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setWindowTitle(@NonNull String value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x10;
+            mWindowTitle = value;
+            return this;
+        }
+
+        /**
+         * Carries additional logging and debugging information when enabled.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setMessages(@NonNull ArrayList<String> value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x20;
+            mMessages = value;
+            return this;
+        }
+
+        /** @see #setMessages */
+        @DataClass.Generated.Member
+        public @NonNull Builder addMessage(@NonNull String value) {
+            if (mMessages == null) setMessages(new ArrayList<>());
+            mMessages.add(value);
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        public @NonNull ScrollCaptureResponse build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x40; // Mark builder used
+
+            if ((mBuilderFieldsSet & 0x1) == 0) {
+                mDescription = "";
+            }
+            if ((mBuilderFieldsSet & 0x2) == 0) {
+                mConnection = null;
+            }
+            if ((mBuilderFieldsSet & 0x4) == 0) {
+                mWindowBounds = null;
+            }
+            if ((mBuilderFieldsSet & 0x8) == 0) {
+                mBoundsInWindow = null;
+            }
+            if ((mBuilderFieldsSet & 0x10) == 0) {
+                mWindowTitle = null;
+            }
+            if ((mBuilderFieldsSet & 0x20) == 0) {
+                mMessages = new ArrayList<>();
+            }
+            ScrollCaptureResponse o = new ScrollCaptureResponse(
+                    mDescription,
+                    mConnection,
+                    mWindowBounds,
+                    mBoundsInWindow,
+                    mWindowTitle,
+                    mMessages);
+            return o;
+        }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & 0x40) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
+        }
+    }
+
+    @DataClass.Generated(
+            time = 1612282689462L,
+            codegenVersion = "1.0.22",
+            sourceFile = "frameworks/base/core/java/android/view/ScrollCaptureResponse.java",
+            inputSignatures = "private @android.annotation.NonNull java.lang.String mDescription\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.MaySetToNull android.view.IScrollCaptureConnection mConnection\nprivate @android.annotation.Nullable android.graphics.Rect mWindowBounds\nprivate @android.annotation.Nullable android.graphics.Rect mBoundsInWindow\nprivate @android.annotation.Nullable java.lang.String mWindowTitle\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"message\") java.util.ArrayList<java.lang.String> mMessages\npublic  boolean isConnected()\nclass ScrollCaptureResponse extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genGetters=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/view/ScrollCaptureSearchResults.java b/core/java/android/view/ScrollCaptureSearchResults.java
new file mode 100644
index 0000000..3469b9d
--- /dev/null
+++ b/core/java/android/view/ScrollCaptureSearchResults.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.NonNull;
+import android.annotation.UiThread;
+import android.graphics.Rect;
+import android.os.CancellationSignal;
+import android.util.IndentingPrintWriter;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * Collects nodes in the view hierarchy which have been identified as scrollable content.
+ *
+ * @hide
+ */
+@UiThread
+public final class ScrollCaptureSearchResults {
+    private final Executor mExecutor;
+    private final List<ScrollCaptureTarget> mTargets;
+    private final CancellationSignal mCancel;
+
+    private Runnable mOnCompleteListener;
+    private int mCompleted;
+    private boolean mComplete = true;
+
+    public ScrollCaptureSearchResults(Executor executor) {
+        mExecutor = executor;
+        mTargets = new ArrayList<>();
+        mCancel = new CancellationSignal();
+    }
+
+    // Public
+
+    /**
+     * Add the given target to the results.
+     *
+     * @param target the target to consider
+     */
+    public void addTarget(@NonNull ScrollCaptureTarget target) {
+        requireNonNull(target);
+
+        mTargets.add(target);
+        mComplete = false;
+        final ScrollCaptureCallback callback = target.getCallback();
+        final Consumer<Rect> consumer = new SearchRequest(target);
+
+        // Defer so the view hierarchy scan completes first
+        mExecutor.execute(
+                () -> callback.onScrollCaptureSearch(mCancel, consumer));
+    }
+
+    public boolean isComplete() {
+        return mComplete;
+    }
+
+    /**
+     * Provides a callback to be invoked as soon as all responses have been received from all
+     * targets to this point.
+     *
+     * @param onComplete listener to add
+     */
+    public void setOnCompleteListener(Runnable onComplete) {
+        if (mComplete) {
+            onComplete.run();
+        } else {
+            mOnCompleteListener = onComplete;
+        }
+    }
+
+    /**
+     * Indicates whether the search results are empty.
+     *
+     * @return true if no targets have been added
+     */
+    public boolean isEmpty() {
+        return mTargets.isEmpty();
+    }
+
+    /**
+     * Force the results to complete now, cancelling any pending requests and calling a complete
+     * listener if provided.
+     */
+    public void finish() {
+        if (!mComplete) {
+            mCancel.cancel();
+            signalComplete();
+        }
+    }
+
+    private void signalComplete() {
+        mComplete = true;
+        mTargets.sort(PRIORITY_ORDER);
+        if (mOnCompleteListener != null) {
+            mOnCompleteListener.run();
+            mOnCompleteListener = null;
+        }
+    }
+
+    @VisibleForTesting
+    public List<ScrollCaptureTarget> getTargets() {
+        return new ArrayList<>(mTargets);
+    }
+
+    /**
+     * Get the top ranked result out of all completed requests.
+     *
+     * @return the top ranked result
+     */
+    public ScrollCaptureTarget getTopResult() {
+        ScrollCaptureTarget target = mTargets.isEmpty() ? null : mTargets.get(0);
+        return target != null && target.getScrollBounds() != null ? target : null;
+    }
+
+    private class SearchRequest implements Consumer<Rect> {
+        private ScrollCaptureTarget mTarget;
+
+        SearchRequest(ScrollCaptureTarget target) {
+            mTarget = target;
+        }
+
+        @Override
+        public void accept(Rect scrollBounds) {
+            if (mTarget == null || mCancel.isCanceled()) {
+                return;
+            }
+            mExecutor.execute(() -> consume(scrollBounds));
+        }
+
+        private void consume(Rect scrollBounds) {
+            if (mTarget == null || mCancel.isCanceled()) {
+                return;
+            }
+            if (!nullOrEmpty(scrollBounds)) {
+                mTarget.setScrollBounds(scrollBounds);
+                mTarget.updatePositionInWindow();
+            }
+            mCompleted++;
+            mTarget = null;
+
+            // All done?
+            if (mCompleted == mTargets.size()) {
+                signalComplete();
+            }
+        }
+    }
+
+    private static final int AFTER = 1;
+    private static final int BEFORE = -1;
+    private static final int EQUAL = 0;
+
+    static final Comparator<ScrollCaptureTarget> PRIORITY_ORDER = (a, b) -> {
+        if (a == null && b == null) {
+            return 0;
+        } else if (a == null || b == null) {
+            return (a == null) ? 1 : -1;
+        }
+
+        boolean emptyScrollBoundsA = nullOrEmpty(a.getScrollBounds());
+        boolean emptyScrollBoundsB = nullOrEmpty(b.getScrollBounds());
+        if (emptyScrollBoundsA || emptyScrollBoundsB) {
+            if (emptyScrollBoundsA && emptyScrollBoundsB) {
+                return EQUAL;
+            }
+            // Prefer the one with a non-empty scroll bounds
+            if (emptyScrollBoundsA) {
+                return AFTER;
+            }
+            return BEFORE;
+        }
+
+        final View viewA = a.getContainingView();
+        final View viewB = b.getContainingView();
+
+        // Prefer any view with scrollCaptureHint="INCLUDE", over one without
+        // This is an escape hatch for the next rule (descendants first)
+        boolean hintIncludeA = hasIncludeHint(viewA);
+        boolean hintIncludeB = hasIncludeHint(viewB);
+        if (hintIncludeA != hintIncludeB) {
+            return (hintIncludeA) ? BEFORE : AFTER;
+        }
+        // If the views are relatives, prefer the descendant. This allows implementations to
+        // leverage nested scrolling APIs by interacting with the innermost scrollable view (as
+        // would happen with touch input).
+        if (isDescendant(viewA, viewB)) {
+            return BEFORE;
+        }
+        if (isDescendant(viewB, viewA)) {
+            return AFTER;
+        }
+
+        // finally, prefer one with larger scroll bounds
+        int scrollAreaA = area(a.getScrollBounds());
+        int scrollAreaB = area(b.getScrollBounds());
+        return (scrollAreaA >= scrollAreaB) ? BEFORE : AFTER;
+    };
+
+    private static int area(Rect r) {
+        return r.width() * r.height();
+    }
+
+    private static boolean nullOrEmpty(Rect r) {
+        return r == null || r.isEmpty();
+    }
+
+    private static boolean hasIncludeHint(View view) {
+        return (view.getScrollCaptureHint() & View.SCROLL_CAPTURE_HINT_INCLUDE) != 0;
+    }
+
+    /**
+     * Determines if {@code otherView} is a descendant of {@code view}.
+     *
+     * @param view      a view
+     * @param otherView another view
+     * @return true if {@code view} is an ancestor of {@code otherView}
+     */
+    private static boolean isDescendant(@NonNull View view, @NonNull View otherView) {
+        if (view == otherView) {
+            return false;
+        }
+        ViewParent otherParent = otherView.getParent();
+        while (otherParent != view && otherParent != null) {
+            otherParent = otherParent.getParent();
+        }
+        return otherParent == view;
+    }
+
+    void dump(IndentingPrintWriter writer) {
+        writer.println("results:");
+        writer.increaseIndent();
+        writer.println("complete: " + isComplete());
+        writer.println("cancelled: " + mCancel.isCanceled());
+        writer.println("targets:");
+        writer.increaseIndent();
+        if (isEmpty()) {
+            writer.println("None");
+        } else {
+            for (int i = 0; i < mTargets.size(); i++) {
+                writer.println("[" + i + "]");
+                writer.increaseIndent();
+                mTargets.get(i).dump(writer);
+                writer.decreaseIndent();
+            }
+            writer.decreaseIndent();
+        }
+        writer.decreaseIndent();
+    }
+}
diff --git a/core/java/android/view/ScrollCaptureSession.java b/core/java/android/view/ScrollCaptureSession.java
index 92617a3..748e7ea 100644
--- a/core/java/android/view/ScrollCaptureSession.java
+++ b/core/java/android/view/ScrollCaptureSession.java
@@ -16,18 +16,15 @@
 
 package android.view;
 
+import static java.util.Objects.requireNonNull;
+
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.graphics.Point;
 import android.graphics.Rect;
 
 /**
  * A session represents the scope of interaction between a {@link ScrollCaptureCallback} and the
- * system during an active scroll capture operation. During the scope of a session, a callback
- * will receive a series of requests for image data. Resources provided here are valid for use
- * until {@link ScrollCaptureCallback#onScrollCaptureEnd(Runnable)}.
- *
- * @hide
+ * system during an active scroll capture operation.
  */
 public class ScrollCaptureSession {
 
@@ -35,22 +32,27 @@
     private final Rect mScrollBounds;
     private final Point mPositionInWindow;
 
-    @Nullable
-    private ScrollCaptureConnection mConnection;
-
-    /** @hide */
-    public ScrollCaptureSession(Surface surface, Rect scrollBounds, Point positionInWindow,
-            ScrollCaptureConnection connection) {
-        mSurface = surface;
-        mScrollBounds = scrollBounds;
-        mPositionInWindow = positionInWindow;
-        mConnection = connection;
+    /**
+     * Constructs a new session instance.
+     *
+     * @param surface the surface to consume generated images
+     * @param scrollBounds the bounds of the capture area within the containing view
+     * @param positionInWindow the offset of scrollBounds within the window
+     */
+    public ScrollCaptureSession(@NonNull Surface surface, @NonNull Rect scrollBounds,
+            @NonNull Point positionInWindow) {
+        mSurface = requireNonNull(surface);
+        mScrollBounds = requireNonNull(scrollBounds);
+        mPositionInWindow = requireNonNull(positionInWindow);
     }
 
     /**
      * Returns a
      * <a href="https://source.android.com/devices/graphics/arch-bq-gralloc">BufferQueue</a> in the
      * form of a {@link Surface} for transfer of image buffers.
+     * <p>
+     * The surface is guaranteed to remain {@link Surface#isValid() valid} until the session
+     * {@link ScrollCaptureCallback#onScrollCaptureEnd(Runnable) ends}.
      *
      * @return the surface for transferring image buffers
      * @throws IllegalStateException if the session has been closed
@@ -80,26 +82,4 @@
     public Point getPositionInWindow() {
         return mPositionInWindow;
     }
-
-    /**
-     * Notify the system that an a buffer has been posted via the getSurface() channel.
-     *
-     * @param frameNumber  the frame number of the queued buffer
-     * @param capturedArea the area captured, relative to scroll bounds
-     */
-    public void notifyBufferSent(long frameNumber, @NonNull Rect capturedArea) {
-        if (mConnection != null) {
-            mConnection.onRequestImageCompleted(frameNumber, capturedArea);
-        }
-    }
-
-    /**
-     * @hide
-     */
-    public void disconnect() {
-        mConnection = null;
-        if (mSurface.isValid()) {
-            mSurface.release();
-        }
-    }
 }
diff --git a/core/java/android/view/ScrollCaptureTarget.java b/core/java/android/view/ScrollCaptureTarget.java
index f3fcabb..4fd4889 100644
--- a/core/java/android/view/ScrollCaptureTarget.java
+++ b/core/java/android/view/ScrollCaptureTarget.java
@@ -22,14 +22,16 @@
 import android.graphics.Matrix;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.os.CancellationSignal;
 
 import com.android.internal.util.FastMath;
 
+import java.io.PrintWriter;
+import java.util.function.Consumer;
+
 /**
  * A target collects the set of contextual information for a ScrollCaptureHandler discovered during
  * a {@link View#dispatchScrollCaptureSearch scroll capture search}.
- *
- * @hide
  */
 public final class ScrollCaptureTarget {
     private final View mContainingView;
@@ -41,7 +43,6 @@
 
     private final float[] mTmpFloatArr = new float[2];
     private final Matrix mMatrixViewLocalToWindow = new Matrix();
-    private final Rect mTmpRect = new Rect();
 
     public ScrollCaptureTarget(@NonNull View scrollTarget, @NonNull Rect localVisibleRect,
             @NonNull Point positionInWindow, @NonNull ScrollCaptureCallback callback) {
@@ -52,7 +53,10 @@
         mPositionInWindow = positionInWindow;
     }
 
-    /** @return the hint that the {@code containing view} had during the scroll capture search */
+    /**
+     * @return the hint that the {@code containing view} had during the scroll capture search
+     * @see View#getScrollCaptureHint()
+     */
     @View.ScrollCaptureHint
     public int getHint() {
         return mHint;
@@ -71,8 +75,7 @@
     }
 
     /**
-     * Returns the un-clipped, visible bounds of the containing view during the scroll capture
-     * search. This is used to determine on-screen area to assist in selecting the primary target.
+     * Returns the visible bounds of the containing view.
      *
      * @return the visible bounds of the {@code containing view} in view-local coordinates
      */
@@ -81,13 +84,17 @@
         return mLocalVisibleRect;
     }
 
-    /** @return the position of the {@code containing view} within the window */
+    /** @return the position of the visible bounds of the containing view within the window */
     @NonNull
     public Point getPositionInWindow() {
         return mPositionInWindow;
     }
 
-    /** @return the {@code scroll bounds} for this {@link ScrollCaptureCallback callback} */
+    /**
+     * @return the {@code scroll bounds} for this {@link ScrollCaptureCallback callback}
+     *
+     * @see ScrollCaptureCallback#onScrollCaptureSearch(CancellationSignal, Consumer)
+     */
     @Nullable
     public Rect getScrollBounds() {
         return mScrollBounds;
@@ -119,8 +126,8 @@
     }
 
     /**
-     * Refresh the value of {@link #mLocalVisibleRect} and {@link #mPositionInWindow} based on the
-     * current state of the {@code containing view}.
+     * Refresh the local visible bounds and it's offset within the window, based on the current
+     * state of the {@code containing view}.
      */
     @UiThread
     public void updatePositionInWindow() {
@@ -132,4 +139,27 @@
         roundIntoPoint(mPositionInWindow, mTmpFloatArr);
     }
 
+    public String toString() {
+        return "ScrollCaptureTarget{" + "view=" + mContainingView
+                + ", callback=" + mCallback
+                + ", scrollBounds=" + mScrollBounds
+                + ", localVisibleRect=" + mLocalVisibleRect
+                + ", positionInWindow=" + mPositionInWindow
+                + "}";
+    }
+
+    void dump(@NonNull PrintWriter writer) {
+        View view = getContainingView();
+        writer.println("view: " + view);
+        writer.println("hint: " + mHint);
+        writer.println("callback: " + mCallback);
+        writer.println("scrollBounds: "
+                + (mScrollBounds == null ? "null" : mScrollBounds.toShortString()));
+        Point inWindow = getPositionInWindow();
+        writer.println("positionInWindow: "
+                + ((inWindow == null) ? "null" : "[" + inWindow.x + "," + inWindow.y + "]"));
+        Rect localVisible = getLocalVisibleRect();
+        writer.println("localVisibleRect: "
+                + (localVisible == null ? "null" : localVisible.toShortString()));
+    }
 }
diff --git a/core/java/android/view/ScrollCaptureTargetResolver.java b/core/java/android/view/ScrollCaptureTargetResolver.java
deleted file mode 100644
index e4316bb..0000000
--- a/core/java/android/view/ScrollCaptureTargetResolver.java
+++ /dev/null
@@ -1,337 +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 android.view;
-
-import android.annotation.AnyThread;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UiThread;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.SystemClock;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-
-import java.util.Queue;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.Consumer;
-
-/**
- * Queries additional state from a list of {@link ScrollCaptureTarget targets} via asynchronous
- * callbacks, then aggregates and reduces the target list to a single target, or null if no target
- * is suitable.
- * <p>
- * The rules for selection are (in order):
- * <ul>
- * <li>prefer getScrollBounds(): non-empty
- * <li>prefer View.getScrollCaptureHint == SCROLL_CAPTURE_HINT_INCLUDE
- * <li>prefer descendants before parents
- * <li>prefer larger area for getScrollBounds() (clipped to view bounds)
- * </ul>
- *
- * <p>
- * All calls to {@link ScrollCaptureCallback#onScrollCaptureSearch} are made on the main thread,
- * with results are queued and consumed to the main thread as well.
- *
- * @see #start(Handler, long, Consumer)
- *
- * @hide
- */
-@UiThread
-public class ScrollCaptureTargetResolver {
-    private static final String TAG = "ScrollCaptureTargetRes";
-
-    private final Object mLock = new Object();
-
-    private final Queue<ScrollCaptureTarget> mTargets;
-    private Handler mHandler;
-    private long mTimeLimitMillis;
-
-    private Consumer<ScrollCaptureTarget> mWhenComplete;
-    private int mPendingBoundsRequests;
-    private long mDeadlineMillis;
-
-    private ScrollCaptureTarget mResult;
-    private boolean mFinished;
-
-    private boolean mStarted;
-
-    private static int area(Rect r) {
-        return r.width() * r.height();
-    }
-
-    private static boolean nullOrEmpty(Rect r) {
-        return r == null || r.isEmpty();
-    }
-
-    /**
-     * Binary operator which selects the best {@link ScrollCaptureTarget}.
-     */
-    private static ScrollCaptureTarget chooseTarget(ScrollCaptureTarget a, ScrollCaptureTarget b) {
-        if (a == null && b == null) {
-            return null;
-        } else if (a == null || b == null) {
-            ScrollCaptureTarget c = (a == null) ? b : a;
-            return c;
-        }
-
-        boolean emptyScrollBoundsA = nullOrEmpty(a.getScrollBounds());
-        boolean emptyScrollBoundsB = nullOrEmpty(b.getScrollBounds());
-        if (emptyScrollBoundsA || emptyScrollBoundsB) {
-            if (emptyScrollBoundsA && emptyScrollBoundsB) {
-                // Both have an empty or null scrollBounds
-                Log.d(TAG, "chooseTarget: (both have empty or null bounds) return " + null);
-                return null;
-            }
-            // Prefer the one with a non-empty scroll bounds
-            if (emptyScrollBoundsA) {
-                Log.d(TAG, "chooseTarget: (a has empty or null bounds) return " + b);
-                return b;
-            }
-            Log.d(TAG, "chooseTarget: (b has empty or null bounds) return " + a);
-            return a;
-        }
-
-        final View viewA = a.getContainingView();
-        final View viewB = b.getContainingView();
-
-        // Prefer any view with scrollCaptureHint="INCLUDE", over one without
-        // This is an escape hatch for the next rule (descendants first)
-        boolean hintIncludeA = hasIncludeHint(viewA);
-        boolean hintIncludeB = hasIncludeHint(viewB);
-        if (hintIncludeA != hintIncludeB) {
-            ScrollCaptureTarget c = (hintIncludeA) ? a : b;
-            Log.d(TAG, "chooseTarget: (has hint=INCLUDE) return " + c);
-            return c;
-        }
-
-        // If the views are relatives, prefer the descendant. This allows implementations to
-        // leverage nested scrolling APIs by interacting with the innermost scrollable view (as
-        // would happen with touch input).
-        if (isDescendant(viewA, viewB)) {
-            Log.d(TAG, "chooseTarget: (b is descendant of a) return " + b);
-            return b;
-        }
-        if (isDescendant(viewB, viewA)) {
-            Log.d(TAG, "chooseTarget: (a is descendant of b) return " + a);
-            return a;
-        }
-
-        // finally, prefer one with larger scroll bounds
-        int scrollAreaA = area(a.getScrollBounds());
-        int scrollAreaB = area(b.getScrollBounds());
-        ScrollCaptureTarget c = (scrollAreaA >= scrollAreaB) ? a : b;
-        Log.d(TAG, "chooseTarget: return " + c);
-        return c;
-    }
-
-    /**
-     * Creates an instance to query and filter {@code target}.
-     *
-     * @param targets   a list of {@link ScrollCaptureTarget} as collected by {@link
-     *                  View#dispatchScrollCaptureSearch}.
-     * @see #start(Handler, long, Consumer)
-     */
-    public ScrollCaptureTargetResolver(Queue<ScrollCaptureTarget> targets) {
-        mTargets = targets;
-    }
-
-    void checkThread() {
-        if (mHandler.getLooper() != Looper.myLooper()) {
-            throw new IllegalStateException("Called from wrong thread! ("
-                    + Thread.currentThread().getName() + ")");
-        }
-    }
-
-    /**
-     * Blocks until a result is returned (after completion or timeout).
-     * <p>
-     * For testing only. Normal usage should receive a callback after calling {@link #start}.
-     */
-    @VisibleForTesting
-    public ScrollCaptureTarget waitForResult() throws InterruptedException {
-        synchronized (mLock) {
-            while (!mFinished) {
-                mLock.wait();
-            }
-        }
-        return mResult;
-    }
-
-    private void supplyResult(ScrollCaptureTarget target) {
-        checkThread();
-        if (mFinished) {
-            return;
-        }
-        mResult = chooseTarget(mResult, target);
-        boolean finish = mPendingBoundsRequests == 0
-                || SystemClock.uptimeMillis() >= mDeadlineMillis;
-        if (finish) {
-            mPendingBoundsRequests = 0;
-            mWhenComplete.accept(mResult);
-            synchronized (mLock) {
-                mFinished = true;
-                mLock.notify();
-            }
-            mWhenComplete = null;
-        }
-    }
-
-    /**
-     * Asks all targets for {@link ScrollCaptureCallback#onScrollCaptureSearch(Consumer)
-     * scrollBounds}, and selects the primary target according to the {@link
-     * #chooseTarget} function.
-     *
-     * @param timeLimitMillis the amount of time to wait for all responses before delivering the top
-     *                        result
-     * @param resultConsumer  the consumer to receive the primary target
-     */
-    @AnyThread
-    public void start(Handler uiHandler, long timeLimitMillis,
-            Consumer<ScrollCaptureTarget> resultConsumer) {
-        synchronized (mLock) {
-            if (mStarted) {
-                throw new IllegalStateException("already started!");
-            }
-            if (timeLimitMillis < 0) {
-                throw new IllegalArgumentException("Time limit must be positive");
-            }
-            mHandler = uiHandler;
-            mTimeLimitMillis = timeLimitMillis;
-            mWhenComplete = resultConsumer;
-            if (mTargets.isEmpty()) {
-                mHandler.post(() -> supplyResult(null));
-                return;
-            }
-            mStarted = true;
-            uiHandler.post(this::run);
-        }
-    }
-
-    private void run() {
-        checkThread();
-
-        mPendingBoundsRequests = mTargets.size();
-        for (ScrollCaptureTarget target : mTargets) {
-            queryTarget(target);
-        }
-        mDeadlineMillis = SystemClock.uptimeMillis() + mTimeLimitMillis;
-        mHandler.postAtTime(mTimeoutRunnable, mDeadlineMillis);
-    }
-
-    private final Runnable mTimeoutRunnable = () -> {
-        checkThread();
-        supplyResult(null);
-    };
-
-    /**
-     * Adds a target to the list and requests {@link ScrollCaptureCallback#onScrollCaptureSearch}
-     * scrollBounds} from it. Results are returned by a call to {@link #onScrollBoundsProvided}.
-     *
-     * @param target the target to add
-     */
-    @UiThread
-    private void queryTarget(@NonNull ScrollCaptureTarget target) {
-        checkThread();
-        final ScrollCaptureCallback callback = target.getCallback();
-        // from the UI thread, request scroll bounds
-        callback.onScrollCaptureSearch(
-                // allow only one callback to onReady.accept():
-                new SingletonConsumer<Rect>(
-                        // Queue and consume on the UI thread
-                        ((scrollBounds) -> mHandler.post(
-                                () -> onScrollBoundsProvided(target, scrollBounds)))));
-    }
-
-    @UiThread
-    private void onScrollBoundsProvided(ScrollCaptureTarget target, @Nullable Rect scrollBounds) {
-        checkThread();
-        if (mFinished) {
-            return;
-        }
-
-        // Record progress.
-        mPendingBoundsRequests--;
-
-        // Remove the timeout.
-        mHandler.removeCallbacks(mTimeoutRunnable);
-
-        boolean doneOrTimedOut = mPendingBoundsRequests == 0
-                || SystemClock.uptimeMillis() >= mDeadlineMillis;
-
-        final View containingView = target.getContainingView();
-        if (!nullOrEmpty(scrollBounds) && containingView.isAggregatedVisible()) {
-            target.updatePositionInWindow();
-            target.setScrollBounds(scrollBounds);
-            supplyResult(target);
-        }
-
-        if (!mFinished) {
-            // Reschedule the timeout.
-            mHandler.postAtTime(mTimeoutRunnable, mDeadlineMillis);
-        }
-    }
-
-    private static boolean hasIncludeHint(View view) {
-        return (view.getScrollCaptureHint() & View.SCROLL_CAPTURE_HINT_INCLUDE) != 0;
-    }
-
-    /**
-     * Determines if {@code otherView} is a descendant of {@code view}.
-     *
-     * @param view      a view
-     * @param otherView another view
-     * @return true if {@code view} is an ancestor of {@code otherView}
-     */
-    private static boolean isDescendant(@NonNull View view, @NonNull View otherView) {
-        if (view == otherView) {
-            return false;
-        }
-        ViewParent otherParent = otherView.getParent();
-        while (otherParent != view && otherParent != null) {
-            otherParent = otherParent.getParent();
-        }
-        return otherParent == view;
-    }
-
-    /**
-     * A safe wrapper for a consumer callbacks intended to accept a single value. It ensures
-     * that the receiver of the consumer does not retain a reference to {@code target} after use nor
-     * cause race conditions by invoking {@link Consumer#accept accept} more than once.
-     */
-    static class SingletonConsumer<T> implements Consumer<T> {
-        final AtomicReference<Consumer<T>> mAtomicRef;
-
-        /**
-         * @param target the target consumer
-         **/
-        SingletonConsumer(Consumer<T> target) {
-            mAtomicRef = new AtomicReference<>(target);
-        }
-
-        @Override
-        public void accept(T t) {
-            final Consumer<T> consumer = mAtomicRef.getAndSet(null);
-            if (consumer != null) {
-                consumer.accept(t);
-            }
-        }
-    }
-}
diff --git a/core/java/android/view/SoundEffectConstants.java b/core/java/android/view/SoundEffectConstants.java
index 8d891bb..f177451 100644
--- a/core/java/android/view/SoundEffectConstants.java
+++ b/core/java/android/view/SoundEffectConstants.java
@@ -16,12 +16,21 @@
 
 package android.view;
 
+import android.media.AudioManager;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import java.util.Random;
+
 /**
- * Constants to be used to play sound effects via {@link View#playSoundEffect(int)} 
+ * Constants to be used to play sound effects via {@link View#playSoundEffect(int)}
  */
 public class SoundEffectConstants {
 
     private SoundEffectConstants() {}
+    private static final Random NAVIGATION_REPEAT_RANDOMIZER = new Random();
+    private static int sLastNavigationRepeatSoundEffectId = -1;
 
     public static final int CLICK = 0;
 
@@ -29,6 +38,14 @@
     public static final int NAVIGATION_UP = 2;
     public static final int NAVIGATION_RIGHT = 3;
     public static final int NAVIGATION_DOWN = 4;
+    /** Sound effect for a repeatedly triggered navigation, e.g. due to long pressing a button */
+    public static final int NAVIGATION_REPEAT_LEFT = 5;
+    /** @see #NAVIGATION_REPEAT_LEFT */
+    public static final int NAVIGATION_REPEAT_UP = 6;
+    /** @see #NAVIGATION_REPEAT_LEFT */
+    public static final int NAVIGATION_REPEAT_RIGHT = 7;
+    /** @see #NAVIGATION_REPEAT_LEFT */
+    public static final int NAVIGATION_REPEAT_DOWN = 8;
 
     /**
      * Get the sonification constant for the focus directions.
@@ -40,7 +57,7 @@
      * @throws {@link IllegalArgumentException} when the passed direction is not one of the
      *     documented values.
      */
-    public static int getContantForFocusDirection(int direction) {
+    public static int getContantForFocusDirection(@View.FocusDirection int direction) {
         switch (direction) {
             case View.FOCUS_RIGHT:
                 return SoundEffectConstants.NAVIGATION_RIGHT;
@@ -56,4 +73,65 @@
         throw new IllegalArgumentException("direction must be one of "
                 + "{FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, FOCUS_BACKWARD}.");
     }
+
+    /**
+     * Get the sonification constant for the focus directions
+     * @param direction One of {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN},
+     *     {@link View#FOCUS_LEFT}, {@link View#FOCUS_RIGHT}, {@link View#FOCUS_FORWARD}
+     *     or {@link View#FOCUS_BACKWARD}
+     * @param repeating True if the user long-presses a direction
+     * @return The appropriate sonification constant
+     * @throws IllegalArgumentException when the passed direction is not one of the
+     *      documented values.
+     */
+    public static int getConstantForFocusDirection(@View.FocusDirection int direction,
+            boolean repeating) {
+        if (repeating) {
+            switch (direction) {
+                case View.FOCUS_RIGHT:
+                    return SoundEffectConstants.NAVIGATION_REPEAT_RIGHT;
+                case View.FOCUS_FORWARD:
+                case View.FOCUS_DOWN:
+                    return SoundEffectConstants.NAVIGATION_REPEAT_DOWN;
+                case View.FOCUS_LEFT:
+                    return SoundEffectConstants.NAVIGATION_REPEAT_LEFT;
+                case View.FOCUS_BACKWARD:
+                case View.FOCUS_UP:
+                    return SoundEffectConstants.NAVIGATION_REPEAT_UP;
+            }
+            throw new IllegalArgumentException("direction must be one of {FOCUS_UP, FOCUS_DOWN, "
+                    + "FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, FOCUS_BACKWARD}.");
+        } else {
+            return getContantForFocusDirection(direction);
+        }
+    }
+
+    /**
+     * @param effectId any of the effect ids defined in {@link SoundEffectConstants}
+     * @return true if the given effect id is a navigation repeat one
+     * @hide
+     */
+    @VisibleForTesting(visibility = Visibility.PACKAGE)
+    public static boolean isNavigationRepeat(int effectId) {
+        return effectId == SoundEffectConstants.NAVIGATION_REPEAT_DOWN
+                || effectId == SoundEffectConstants.NAVIGATION_REPEAT_LEFT
+                || effectId == SoundEffectConstants.NAVIGATION_REPEAT_RIGHT
+                || effectId == SoundEffectConstants.NAVIGATION_REPEAT_UP;
+    }
+
+    /**
+     * @return The next navigation repeat sound effect id, chosen at random in a non-repeating
+     * fashion
+     * @hide
+     */
+    @VisibleForTesting(visibility = Visibility.PACKAGE)
+    public static int nextNavigationRepeatSoundEffectId() {
+        int next = NAVIGATION_REPEAT_RANDOMIZER.nextInt(
+                AudioManager.NUM_NAVIGATION_REPEAT_SOUND_EFFECTS - 1);
+        if (next >= sLastNavigationRepeatSoundEffectId) {
+            next++;
+        }
+        sLastNavigationRepeatSoundEffectId = next;
+        return AudioManager.getNthNavigationRepeatSoundEffect(next);
+    }
 }
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 0832578..03dd100 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -3504,64 +3504,4 @@
     public static Transaction getGlobalTransaction() {
         return sGlobalTransaction;
     }
-
-    /**
-     * Wrapper for sending blur data to SurfaceFlinger.
-     * @hide
-     */
-    public static final class BlurRegion {
-        public int blurRadius;
-        public float cornerRadiusTL;
-        public float cornerRadiusTR;
-        public float cornerRadiusBL;
-        public float cornerRadiusBR;
-        public float alpha = 1;
-        public boolean visible = true;
-        public final Rect rect = new Rect();
-
-        private final float[] mFloatArray = new float[10];
-
-        public BlurRegion() {
-        }
-
-        public BlurRegion(BlurRegion other) {
-            rect.set(other.rect);
-            blurRadius = other.blurRadius;
-            alpha = other.alpha;
-            cornerRadiusTL = other.cornerRadiusTL;
-            cornerRadiusTR = other.cornerRadiusTR;
-            cornerRadiusBL = other.cornerRadiusBL;
-            cornerRadiusBR = other.cornerRadiusBR;
-        }
-
-        /**
-         * Serializes this class into a float array that's more JNI friendly.
-         */
-        public float[] toFloatArray() {
-            mFloatArray[0] = blurRadius;
-            mFloatArray[1] = alpha;
-            mFloatArray[2] = rect.left;
-            mFloatArray[3] = rect.top;
-            mFloatArray[4] = rect.right;
-            mFloatArray[5] = rect.bottom;
-            mFloatArray[6] = cornerRadiusTL;
-            mFloatArray[7] = cornerRadiusTR;
-            mFloatArray[8] = cornerRadiusBL;
-            mFloatArray[9] = cornerRadiusBR;
-            return mFloatArray;
-        }
-
-        @Override
-        public String toString() {
-            return "BlurRegion{"
-                    + "blurRadius=" + blurRadius
-                    + ", corners={" + cornerRadiusTL
-                    + "," + cornerRadiusTR
-                    + "," + cornerRadiusBL
-                    + "," + cornerRadiusBR
-                    + "}, alpha=" + alpha
-                    + ", rect=" + rect
-                    + "}";
-        }
-    }
 }
diff --git a/core/java/android/view/SurfaceControlFpsListener.java b/core/java/android/view/SurfaceControlFpsListener.java
new file mode 100644
index 0000000..517b0fb
--- /dev/null
+++ b/core/java/android/view/SurfaceControlFpsListener.java
@@ -0,0 +1,93 @@
+/*
+ * 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.view;
+
+import android.annotation.NonNull;
+
+/**
+ * Listener for sampling the frames per second for a SurfaceControl and its children.
+ * This should only be used by a system component that needs to listen to a SurfaceControl's
+ * tree's FPS when it is not actively submitting transactions for that SurfaceControl.
+ * Otherwise, ASurfaceTransaction_OnComplete callbacks should be used.
+ *
+ * @hide
+ */
+public abstract class SurfaceControlFpsListener {
+    private long mNativeListener;
+
+    public SurfaceControlFpsListener() {
+        mNativeListener = nativeCreate(this);
+    }
+
+    protected void destroy() {
+        if (mNativeListener == 0) {
+            return;
+        }
+        unregister();
+        nativeDestroy(mNativeListener);
+        mNativeListener = 0;
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            destroy();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    /**
+     * Reports the fps from the registered SurfaceControl
+     */
+    public abstract void onFpsReported(float fps);
+
+    /**
+     * Registers the sampling listener.
+     */
+    public void register(@NonNull SurfaceControl layer) {
+        if (mNativeListener == 0) {
+            return;
+        }
+
+        nativeRegister(mNativeListener, layer.mNativeObject);
+    }
+
+    /**
+     * Unregisters the sampling listener.
+     */
+    public void unregister() {
+        if (mNativeListener == 0) {
+            return;
+        }
+        nativeUnregister(mNativeListener);
+    }
+
+    /**
+     * Dispatch the collected sample.
+     *
+     * Called from native code on a binder thread.
+     */
+    private static void dispatchOnFpsReported(SurfaceControlFpsListener listener, float fps) {
+        listener.onFpsReported(fps);
+    }
+
+    private static native long nativeCreate(SurfaceControlFpsListener thiz);
+    private static native void nativeDestroy(long ptr);
+    private static native void nativeRegister(long ptr, long layerObject);
+    private static native void nativeUnregister(long ptr);
+}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index ec7e4c1..9688c67 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -544,6 +544,7 @@
         // recreate this Surface, so only release it when we are fully
         // detached.
         if (mSurfacePackage != null) {
+            mTmpTransaction.reparent(mSurfacePackage.getSurfaceControl(), null).apply();
             mSurfacePackage.release();
             mSurfacePackage = null;
         }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3789324..ebef464 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -184,10 +184,10 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
-import java.util.Queue;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
 import java.util.function.Predicate;
 
 /**
@@ -1484,7 +1484,6 @@
      *
      * @see #getScrollCaptureHint()
      * @see #setScrollCaptureHint(int)
-     * @hide
      */
     public static final int SCROLL_CAPTURE_HINT_AUTO = 0;
 
@@ -1495,7 +1494,6 @@
      *
      * @see #getScrollCaptureHint()
      * @see #setScrollCaptureHint(int)
-     * @hide
      */
     public static final int SCROLL_CAPTURE_HINT_EXCLUDE = 0x1;
 
@@ -1506,7 +1504,6 @@
      *
      * @see #getScrollCaptureHint()
      * @see #setScrollCaptureHint(int)
-     * @hide
      */
     public static final int SCROLL_CAPTURE_HINT_INCLUDE = 0x2;
 
@@ -1517,7 +1514,6 @@
      *
      * @see #getScrollCaptureHint()
      * @see #setScrollCaptureHint(int)
-     * @hide
      */
     public static final int SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS = 0x4;
 
@@ -30053,8 +30049,6 @@
      * Returns the current scroll capture hint for this view.
      *
      * @return the current scroll capture hint
-     *
-     * @hide
      */
     @ScrollCaptureHint
     public int getScrollCaptureHint() {
@@ -30067,8 +30061,6 @@
      * scroll capture targets.
      *
      * @param hint the scrollCaptureHint flags value to set
-     *
-     * @hide
      */
     public void setScrollCaptureHint(@ScrollCaptureHint int hint) {
         mPrivateFlags4 &= ~PFLAG4_SCROLL_CAPTURE_HINT_MASK;
@@ -30088,10 +30080,8 @@
      * setting a custom callback to help ensure it is selected as the target.
      *
      * @param callback the new callback to assign
-     *
-     * @hide
      */
-    public void setScrollCaptureCallback(@Nullable ScrollCaptureCallback callback) {
+    public final void setScrollCaptureCallback(@Nullable ScrollCaptureCallback callback) {
         getListenerInfo().mScrollCaptureCallback = callback;
     }
 
@@ -30110,29 +30100,54 @@
     }
 
     /**
+     * Dispatch a scroll capture search request down the view hierarchy.
+     *
+     * @param localVisibleRect the visible area of this ViewGroup in local coordinates, according to
+     *                         the parent
+     * @param windowOffset     the offset of this view within the window
+     * @param targets          accepts potential scroll capture targets; {@link Consumer#accept
+     *                         results.accept} may be called zero or more times on the calling
+     *                         thread before onScrollCaptureSearch returns
+     */
+    public void dispatchScrollCaptureSearch(
+            @NonNull Rect localVisibleRect, @NonNull Point windowOffset,
+            @NonNull Consumer<ScrollCaptureTarget> targets) {
+        onScrollCaptureSearch(localVisibleRect, windowOffset, targets);
+    }
+
+    /**
      * Called when scroll capture is requested, to search for appropriate content to scroll. If
      * applicable, this view adds itself to the provided list for consideration, subject to the
      * flags set by {@link #setScrollCaptureHint}.
      *
      * @param localVisibleRect the local visible rect of this view
      * @param windowOffset     the offset of localVisibleRect within the window
-     * @param targets          a queue which collects potential targets
-     *
+     * @param targets          accepts potential scroll capture targets; {@link Consumer#accept
+     *                         results.accept} may be called zero or more times on the calling
+     *                         thread before onScrollCaptureSearch returns
      * @throws IllegalStateException if this view is not attached to a window
-     * @hide
      */
-    public void dispatchScrollCaptureSearch(@NonNull Rect localVisibleRect,
-            @NonNull Point windowOffset, @NonNull Queue<ScrollCaptureTarget> targets) {
+    public void onScrollCaptureSearch(@NonNull Rect localVisibleRect,
+            @NonNull Point windowOffset, @NonNull Consumer<ScrollCaptureTarget> targets) {
         int hint = getScrollCaptureHint();
         if ((hint & SCROLL_CAPTURE_HINT_EXCLUDE) != 0) {
             return;
         }
+        boolean rectIsVisible = true;
+
+        // Apply clipBounds if present.
+        if (mClipBounds != null) {
+            rectIsVisible = localVisibleRect.intersect(mClipBounds);
+        }
+        if (!rectIsVisible) {
+            return;
+        }
 
         // Get a callback provided by the framework, library or application.
         ScrollCaptureCallback callback =
                 (mListenerInfo == null) ? null : mListenerInfo.mScrollCaptureCallback;
 
-        // Try internal support for standard scrolling containers.
+        // Try framework support for standard scrolling containers.
         if (callback == null) {
             callback = createScrollCaptureCallbackInternal(localVisibleRect, windowOffset);
         }
@@ -30142,7 +30157,7 @@
             // Add to the list for consideration
             Point offset = new Point(windowOffset.x, windowOffset.y);
             Rect rect = new Rect(localVisibleRect);
-            targets.add(new ScrollCaptureTarget(this, rect, offset, callback));
+            targets.accept(new ScrollCaptureTarget(this, rect, offset, callback));
         }
     }
 
diff --git a/core/java/android/view/ViewFrameInfo.java b/core/java/android/view/ViewFrameInfo.java
index 890d071..d4aaa61 100644
--- a/core/java/android/view/ViewFrameInfo.java
+++ b/core/java/android/view/ViewFrameInfo.java
@@ -58,8 +58,8 @@
     public void populateFrameInfo(FrameInfo frameInfo) {
         frameInfo.frameInfo[FrameInfo.FLAGS] |= flags;
         frameInfo.frameInfo[FrameInfo.DRAW_START] = drawStart;
-        frameInfo.frameInfo[FrameInfo.OLDEST_INPUT_EVENT] = oldestInputEventTime;
-        frameInfo.frameInfo[FrameInfo.NEWEST_INPUT_EVENT] = newestInputEventTime;
+        // TODO(b/169866723): Use InputEventAssigner
+        frameInfo.frameInfo[FrameInfo.INPUT_EVENT_ID] = newestInputEventTime;
     }
 
     /**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 37bea58..38a5937 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -77,7 +77,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Queue;
+import java.util.function.Consumer;
 import java.util.function.Predicate;
 
 /**
@@ -7463,92 +7463,73 @@
     }
 
     /**
-     * Offsets the given rectangle in parent's local coordinates into child's coordinate space
-     * and clips the result to the child View's bounds, padding and clipRect if appropriate. If the
-     * resulting rectangle is not empty, the request is forwarded to the child.
-     * <p>
-     * Note: This method does not account for any static View transformations which may be
-     * applied to the child view.
-     *
-     * @param child            the child to dispatch to
-     * @param localVisibleRect the visible (clipped) area of this ViewGroup, in local coordinates
-     * @param windowOffset     the offset of localVisibleRect within the window
-     * @param targets          a queue to collect located targets
-     */
-    private void dispatchTransformedScrollCaptureSearch(View child, Rect localVisibleRect,
-            Point windowOffset, Queue<ScrollCaptureTarget> targets) {
-
-        // copy local visible rect for modification and dispatch
-        final Rect childVisibleRect = getTempRect();
-        childVisibleRect.set(localVisibleRect);
-
-        // transform to child coords
-        final Point childWindowOffset = getTempPoint();
-        childWindowOffset.set(windowOffset.x, windowOffset.y);
-
-        final int dx = child.mLeft - mScrollX;
-        final int dy = child.mTop - mScrollY;
-
-        childVisibleRect.offset(-dx, -dy);
-        childWindowOffset.offset(dx, dy);
-
-        boolean rectIsVisible = true;
-        final int width = mRight - mLeft;
-        final int height = mBottom - mTop;
-
-        // Clip to child bounds
-        if (getClipChildren()) {
-            rectIsVisible = childVisibleRect.intersect(0, 0, child.getWidth(), child.getHeight());
-        }
-
-        // Clip to child padding.
-        if (rectIsVisible && (child instanceof ViewGroup)
-                && ((ViewGroup) child).getClipToPadding()) {
-            rectIsVisible = childVisibleRect.intersect(
-                    child.mPaddingLeft, child.mPaddingTop,
-                    child.getWidth() - child.mPaddingRight,
-                    child.getHeight() - child.mPaddingBottom);
-        }
-        // Clip to child clipBounds.
-        if (rectIsVisible && child.mClipBounds != null) {
-            rectIsVisible = childVisibleRect.intersect(child.mClipBounds);
-        }
-        if (rectIsVisible) {
-            child.dispatchScrollCaptureSearch(childVisibleRect, childWindowOffset, targets);
-        }
-    }
-
-    /**
      * Handle the scroll capture search request by checking this view if applicable, then to each
      * child view.
      *
      * @param localVisibleRect the visible area of this ViewGroup in local coordinates, according to
      *                         the parent
      * @param windowOffset     the offset of this view within the window
-     * @param targets          the collected list of scroll capture targets
-     *
-     * @hide
+     * @param targets          accepts potential scroll capture targets; {@link Consumer#accept
+     *                         results.accept} may be called zero or more times on the calling
+     *                         thread before onScrollCaptureSearch returns
      */
     @Override
     public void dispatchScrollCaptureSearch(
             @NonNull Rect localVisibleRect, @NonNull Point windowOffset,
-            @NonNull Queue<ScrollCaptureTarget> targets) {
+            @NonNull Consumer<ScrollCaptureTarget> targets) {
+
+        // copy local visible rect for modification and dispatch
+        final Rect rect = getTempRect();
+        rect.set(localVisibleRect);
+
+        if (getClipToPadding()) {
+            rect.inset(mPaddingLeft, mPaddingTop, mPaddingRight, mPaddingBottom);
+        }
 
         // Dispatch to self first.
         super.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, targets);
 
-        // Then dispatch to children, if not excluding descendants.
-        if ((getScrollCaptureHint() & SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS) == 0) {
-            final int childCount = getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                View child = getChildAt(i);
-                // Only visible views can be captured.
-                if (child.getVisibility() != View.VISIBLE) {
-                    continue;
-                }
-                // Transform to child coords and dispatch
-                dispatchTransformedScrollCaptureSearch(child, localVisibleRect, windowOffset,
-                        targets);
+        // Skip children if descendants excluded.
+        if ((getScrollCaptureHint() & SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS) != 0) {
+            return;
+        }
+
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View child = getChildAt(i);
+            // Only visible views can be captured.
+            if (child.getVisibility() != View.VISIBLE) {
+                continue;
+            }
+            // Offset the given rectangle (in parent's local coordinates) into child's coordinate
+            // space and clip the result to the child View's bounds, padding and clipRect as needed.
+            // If the resulting rectangle is not empty, the request is forwarded to the child.
+
+            // copy local visible rect for modification and dispatch
+            final Rect childVisibleRect = getTempRect();
+            childVisibleRect.set(localVisibleRect);
+
+            // transform to child coords
+            final Point childWindowOffset = getTempPoint();
+            childWindowOffset.set(windowOffset.x, windowOffset.y);
+
+            final int dx = child.mLeft - mScrollX;
+            final int dy = child.mTop - mScrollY;
+
+            childVisibleRect.offset(-dx, -dy);
+            childWindowOffset.offset(dx, dy);
+
+            boolean rectIsVisible = true;
+
+            // Clip to child bounds
+            if (getClipChildren()) {
+                rectIsVisible = childVisibleRect.intersect(0, 0, child.getWidth(),
+                        child.getHeight());
+            }
+
+            // Clip to child padding.
+            if (rectIsVisible) {
+                child.dispatchScrollCaptureSearch(childVisibleRect, childWindowOffset, targets);
             }
         }
     }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 144691d..f8e65bd 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -141,6 +141,7 @@
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
+import android.util.IndentingPrintWriter;
 import android.util.Log;
 import android.util.LongArray;
 import android.util.MergedConfiguration;
@@ -202,6 +203,7 @@
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -274,6 +276,11 @@
      */
     private static final int CONTENT_CAPTURE_ENABLED_FALSE = 2;
 
+    /**
+     * Maximum time to wait for {@link View#dispatchScrollCaptureSearch} to complete.
+     */
+    private static final int SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS = 2500;
+
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
 
@@ -323,6 +330,8 @@
     private boolean mForceDisableBLAST;
     private boolean mEnableTripleBuffering;
 
+    private boolean mFastScrollSoundEffectsEnabled;
+
     /**
      * Signals that compatibility booleans have been initialized according to
      * target SDK versions.
@@ -666,8 +675,6 @@
     private final InsetsController mInsetsController;
     private final ImeFocusController mImeFocusController;
 
-    private ScrollCaptureConnection mScrollCaptureConnection;
-
     private boolean mIsSurfaceOpaque;
 
     private final BackgroundBlurDrawable.Aggregator mBlurRegionAggregator =
@@ -681,12 +688,6 @@
         return mImeFocusController;
     }
 
-    /** @return The current {@link ScrollCaptureConnection} for this instance, if any is active. */
-    @Nullable
-    public ScrollCaptureConnection getScrollCaptureConnection() {
-        return mScrollCaptureConnection;
-    }
-
     private final GestureExclusionTracker mGestureExclusionTracker = new GestureExclusionTracker();
 
     private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;
@@ -728,6 +729,8 @@
 
     private HashSet<ScrollCaptureCallback> mRootScrollCaptureCallbacks;
 
+    private long mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS;
+
     /**
      * Increment this value when the surface has been replaced.
      */
@@ -813,6 +816,10 @@
 
         loadSystemProperties();
         mImeFocusController = new ImeFocusController(this);
+        AudioManager audioManager = mContext.getSystemService(AudioManager.class);
+        mFastScrollSoundEffectsEnabled = audioManager.areNavigationRepeatSoundEffectsEnabled();
+
+        mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS;
     }
 
     public static void addFirstDrawHandler(Runnable callback) {
@@ -3962,11 +3969,12 @@
     }
 
     private void addFrameCallbackIfNeeded() {
-        boolean nextDrawUseBlastSync = mNextDrawUseBlastSync;
-        boolean hasBlur = mBlurRegionAggregator.hasRegions();
-        boolean reportNextDraw = mReportNextDraw;
+        final boolean nextDrawUseBlastSync = mNextDrawUseBlastSync;
+        final boolean reportNextDraw = mReportNextDraw;
+        final boolean hasBlurUpdates = mBlurRegionAggregator.hasUpdates();
+        final boolean needsCallbackForBlur = hasBlurUpdates || mBlurRegionAggregator.hasRegions();
 
-        if (!nextDrawUseBlastSync && !reportNextDraw && !hasBlur) {
+        if (!nextDrawUseBlastSync && !reportNextDraw && !needsCallbackForBlur) {
             return;
         }
 
@@ -3974,18 +3982,22 @@
             Log.d(mTag, "Creating frameDrawingCallback"
                     + " nextDrawUseBlastSync=" + nextDrawUseBlastSync
                     + " reportNextDraw=" + reportNextDraw
-                    + " hasBlur=" + hasBlur);
+                    + " hasBlurUpdates=" + hasBlurUpdates);
         }
 
-        // The callback will run on a worker thread pool from the render thread.
+        final BackgroundBlurDrawable.BlurRegion[] blurRegionsForFrame =
+                needsCallbackForBlur ?  mBlurRegionAggregator.getBlurRegionsCopyForRT() : null;
+
+        // The callback will run on the render thread.
         HardwareRenderer.FrameDrawingCallback frameDrawingCallback = frame -> {
             if (DEBUG_BLAST) {
                 Log.d(mTag, "Received frameDrawingCallback frameNum=" + frame + "."
                         + " Creating transactionCompleteCallback=" + nextDrawUseBlastSync);
             }
 
-            if (hasBlur) {
-                mBlurRegionAggregator.dispatchBlurTransactionIfNeeded(frame);
+            if (needsCallbackForBlur) {
+                mBlurRegionAggregator
+                    .dispatchBlurTransactionIfNeeded(frame, blurRegionsForFrame, hasBlurUpdates);
             }
 
             if (mBlastBufferQueue == null) {
@@ -6081,8 +6093,10 @@
                                     v, mTempRect);
                         }
                         if (v.requestFocus(direction, mTempRect)) {
-                            playSoundEffect(SoundEffectConstants
-                                    .getContantForFocusDirection(direction));
+                            boolean isFastScrolling = event.getRepeatCount() > 0;
+                            playSoundEffect(
+                                    SoundEffectConstants.getConstantForFocusDirection(direction,
+                                            isFastScrolling));
                             return true;
                         }
                     }
@@ -7743,20 +7757,31 @@
         try {
             final AudioManager audioManager = getAudioManager();
 
+            if (mFastScrollSoundEffectsEnabled
+                    && SoundEffectConstants.isNavigationRepeat(effectId)) {
+                audioManager.playSoundEffect(
+                        SoundEffectConstants.nextNavigationRepeatSoundEffectId());
+                return;
+            }
+
             switch (effectId) {
                 case SoundEffectConstants.CLICK:
                     audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
                     return;
                 case SoundEffectConstants.NAVIGATION_DOWN:
+                case SoundEffectConstants.NAVIGATION_REPEAT_DOWN:
                     audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
                     return;
                 case SoundEffectConstants.NAVIGATION_LEFT:
+                case SoundEffectConstants.NAVIGATION_REPEAT_LEFT:
                     audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
                     return;
                 case SoundEffectConstants.NAVIGATION_RIGHT:
+                case SoundEffectConstants.NAVIGATION_REPEAT_RIGHT:
                     audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
                     return;
                 case SoundEffectConstants.NAVIGATION_UP:
+                case SoundEffectConstants.NAVIGATION_REPEAT_UP:
                     audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
                     return;
                 default:
@@ -9206,9 +9231,9 @@
      * Collect and include any ScrollCaptureCallback instances registered with the window.
      *
      * @see #addScrollCaptureCallback(ScrollCaptureCallback)
-     * @param targets the search queue for targets
+     * @param results an object to collect the results of the search
      */
-    private void collectRootScrollCaptureTargets(Queue<ScrollCaptureTarget> targets) {
+    private void collectRootScrollCaptureTargets(ScrollCaptureSearchResults results) {
         if (mRootScrollCaptureCallbacks == null) {
             return;
         }
@@ -9216,26 +9241,45 @@
             // Add to the list for consideration
             Point offset = new Point(mView.getLeft(), mView.getTop());
             Rect rect = new Rect(0, 0, mView.getWidth(), mView.getHeight());
-            targets.add(new ScrollCaptureTarget(mView, rect, offset, cb));
+            results.addTarget(new ScrollCaptureTarget(mView, rect, offset, cb));
         }
     }
 
     /**
-     * Handles an inbound request for scroll capture from the system. If a client is not already
-     * active, a search will be dispatched through the view tree to locate scrolling content.
+     * Update the timeout for scroll capture requests. Only affects this view root.
+     * The default value is {@link #SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS}.
+     *
+     * @param timeMillis the new timeout in milliseconds
+     */
+    public void setScrollCaptureRequestTimeout(int timeMillis) {
+        mScrollCaptureRequestTimeout = timeMillis;
+    }
+
+    /**
+     * Get the current timeout for scroll capture requests.
+     *
+     * @return the timeout in milliseconds
+     */
+    public long getScrollCaptureRequestTimeout() {
+        return mScrollCaptureRequestTimeout;
+    }
+
+    /**
+     * Handles an inbound request for scroll capture from the system. A search will be
+     * dispatched through the view tree to locate scrolling content.
      * <p>
-     * Either {@link IScrollCaptureCallbacks#onConnected(IScrollCaptureConnection, Rect,
-     * Point)} or {@link IScrollCaptureCallbacks#onUnavailable()} will be returned
-     * depending on the results of the search.
+     * A call to {@link IScrollCaptureCallbacks#onScrollCaptureResponse(ScrollCaptureResponse)}
+     * will follow.
      *
      * @param callbacks to receive responses
-     * @see ScrollCaptureTargetResolver
+     * @see ScrollCaptureTargetSelector
      */
     public void handleScrollCaptureRequest(@NonNull IScrollCaptureCallbacks callbacks) {
-        LinkedList<ScrollCaptureTarget> targetList = new LinkedList<>();
+        ScrollCaptureSearchResults results =
+                new ScrollCaptureSearchResults(mContext.getMainExecutor());
 
         // Window (root) level callbacks
-        collectRootScrollCaptureTargets(targetList);
+        collectRootScrollCaptureTargets(results);
 
         // Search through View-tree
         View rootView = getView();
@@ -9243,58 +9287,70 @@
             Point point = new Point();
             Rect rect = new Rect(0, 0, rootView.getWidth(), rootView.getHeight());
             getChildVisibleRect(rootView, rect, point);
-            rootView.dispatchScrollCaptureSearch(rect, point, targetList);
+            rootView.dispatchScrollCaptureSearch(rect, point, results::addTarget);
         }
-
-        // No-op path. Scroll capture not offered for this window.
-        if (targetList.isEmpty()) {
-            dispatchScrollCaptureSearchResult(callbacks, null);
-            return;
+        Runnable onComplete = () -> dispatchScrollCaptureSearchResult(callbacks, results);
+        results.setOnCompleteListener(onComplete);
+        if (!results.isComplete()) {
+            mHandler.postDelayed(results::finish, getScrollCaptureRequestTimeout());
         }
-
-        // Request scrollBounds from each of the targets.
-        // Continues with the consumer once all responses are consumed, or the timeout expires.
-        ScrollCaptureTargetResolver resolver = new ScrollCaptureTargetResolver(targetList);
-        resolver.start(mHandler, 1000,
-                (selected) -> dispatchScrollCaptureSearchResult(callbacks, selected));
     }
 
     /** Called by {@link #handleScrollCaptureRequest} when a result is returned */
     private void dispatchScrollCaptureSearchResult(
             @NonNull IScrollCaptureCallbacks callbacks,
-            @Nullable ScrollCaptureTarget selectedTarget) {
+            @NonNull ScrollCaptureSearchResults results) {
 
-        // If timeout or no eligible targets found.
+        ScrollCaptureTarget selectedTarget = results.getTopResult();
+
+        ScrollCaptureResponse.Builder response = new ScrollCaptureResponse.Builder();
+        response.setWindowTitle(getTitle().toString());
+
+        StringWriter writer =  new StringWriter();
+        IndentingPrintWriter pw = new IndentingPrintWriter(writer);
+        results.dump(pw);
+        pw.flush();
+        response.addMessage(writer.toString());
+
         if (selectedTarget == null) {
+            response.setDescription("No scrollable targets found in window");
             try {
-                if (DEBUG_SCROLL_CAPTURE) {
-                    Log.d(TAG, "scrollCaptureSearch returned no targets available.");
-                }
-                callbacks.onUnavailable();
+                callbacks.onScrollCaptureResponse(response.build());
             } catch (RemoteException e) {
-                if (DEBUG_SCROLL_CAPTURE) {
-                    Log.w(TAG, "Failed to send scroll capture search result.", e);
-                }
+                Log.e(TAG, "Failed to send scroll capture search result", e);
             }
             return;
         }
 
-        // Create a client instance and return it to the caller
-        mScrollCaptureConnection = new ScrollCaptureConnection(selectedTarget, callbacks);
+        response.setDescription("Connected");
+
+        // Compute area covered by scrolling content within window
+        Rect boundsInWindow = new Rect();
+        View containingView = selectedTarget.getContainingView();
+        containingView.getLocationInWindow(mAttachInfo.mTmpLocation);
+        boundsInWindow.set(selectedTarget.getScrollBounds());
+        boundsInWindow.offset(mAttachInfo.mTmpLocation[0], mAttachInfo.mTmpLocation[1]);
+        response.setBoundsInWindow(boundsInWindow);
+
+        // Compute the area on screen covered by the window
+        Rect boundsOnScreen = new Rect();
+        mView.getLocationOnScreen(mAttachInfo.mTmpLocation);
+        boundsOnScreen.set(0, 0, mView.getWidth(), mView.getHeight());
+        boundsOnScreen.offset(mAttachInfo.mTmpLocation[0], mAttachInfo.mTmpLocation[1]);
+        response.setWindowBounds(boundsOnScreen);
+
+        // Create a connection and return it to the caller
+        ScrollCaptureConnection connection = new ScrollCaptureConnection(
+                mView.getContext().getMainExecutor(), selectedTarget, callbacks);
+        response.setConnection(connection);
+
         try {
-            if (DEBUG_SCROLL_CAPTURE) {
-                Log.d(TAG, "scrollCaptureSearch returning client: " + getScrollCaptureConnection());
-            }
-            callbacks.onConnected(
-                    mScrollCaptureConnection,
-                    selectedTarget.getScrollBounds(),
-                    selectedTarget.getPositionInWindow());
+            callbacks.onScrollCaptureResponse(response.build());
         } catch (RemoteException e) {
             if (DEBUG_SCROLL_CAPTURE) {
-                Log.w(TAG, "Failed to send scroll capture search result.", e);
+                Log.w(TAG, "Failed to send scroll capture search response.", e);
             }
-            mScrollCaptureConnection.disconnect();
-            mScrollCaptureConnection = null;
+            connection.close();
         }
     }
 
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 4ecdd78..cf5ec8d 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1716,13 +1716,22 @@
      * For the blur region to be visible, the window has to be translucent. See
      * {@link android.R.styleable#Window_windowIsTranslucent}.
      *
-     * Note the difference with {@link android.view.WindowManager.LayoutParams#blurBehindRadius},
+     * Note the difference with {@link WindowManager.LayoutParams#setBlurBehindRadius},
      * which blurs the whole screen behind the window. Background blur blurs the screen behind
      * only within the bounds of the window.
      *
+     * Some devices might not support cross-window blur due to GPU limitations. It can also be
+     * disabled at runtime, e.g. during battery saving mode, when multimedia tunneling is used or
+     * when minimal post processing is requested. In such situations, no blur will be computed or
+     * drawn, resulting in a transparent window background. To avoid this, the app might want to
+     * change its theme to one that does not use blurs. To listen for cross-window blur
+     * enabled/disabled events, use {@link WindowManager#addCrossWindowBlurEnabledListener}.
+     *
      * @param blurRadius The blur radius to use for window background blur in pixels
      *
      * @see android.R.styleable#Window_windowBackgroundBlurRadius
+     * @see WindowManager.LayoutParams#setBlurBehindRadius
+     * @see WindowManager#addCrossWindowBlurEnabledListener
      */
     public void setBackgroundBlurRadius(int blurRadius) {}
 
@@ -2621,7 +2630,6 @@
      * callback with the root view of the window.
      *
      * @param callback the callback to add
-     * @hide
      */
     public void registerScrollCaptureCallback(@NonNull ScrollCaptureCallback callback) {
     }
@@ -2630,7 +2638,6 @@
      * Unregisters a {@link ScrollCaptureCallback} previously registered with this window.
      *
      * @param callback the callback to remove
-     * @hide
      */
     public void unregisterScrollCaptureCallback(@NonNull ScrollCaptureCallback callback) {
     }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 9e87c95..1819da4 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -82,6 +82,7 @@
 
 import android.Manifest.permission;
 import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -120,6 +121,7 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
+import java.util.function.Consumer;
 
 /**
  * The interface that apps use to talk to the window manager.
@@ -808,6 +810,64 @@
         return DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
     }
 
+    /**
+     * Returns whether cross-window blur is currently enabled. This affects both window blur behind
+     * (see {@link LayoutParams#setBlurBehindRadius}) and window background blur (see
+     * {@link Window#setBackgroundBlurRadius}).
+     *
+     * Cross-window blur might not be supported by some devices due to GPU limitations. It can also
+     * be disabled at runtime, e.g. during battery saving mode, when multimedia tunneling is used or
+     * when minimal post processing is requested. In such situations, no blur will be computed or
+     * drawn, so the blur target area will not be blurred. To handle this, the app might want to
+     * change its theme to one that does not use blurs. To listen for cross-window blur
+     * enabled/disabled events, use {@link #addCrossWindowBlurEnabledListener}.
+     *
+     * @see #addCrossWindowBlurEnabledListener
+     * @see LayoutParams#setBlurBehindRadius
+     * @see Window#setBackgroundBlurRadius
+     */
+    default boolean isCrossWindowBlurEnabled() {
+        return false;
+    }
+
+    /**
+     * Adds a listener, which will be called when cross-window blurs are enabled/disabled at
+     * runtime. This affects both window blur behind (see {@link LayoutParams#setBlurBehindRadius})
+     * and window background blur (see {@link Window#setBackgroundBlurRadius}).
+     *
+     * Cross-window blur might not be supported by some devices due to GPU limitations. It can also
+     * be disabled at runtime, e.g. during battery saving mode, when multimedia tunneling is used or
+     * when minimal post processing is requested. In such situations, no blur will be computed or
+     * drawn, so the blur target area will not be blurred. To handle this, the app might want to
+     * change its theme to one that does not use blurs.
+     *
+     * The listener will be called on the main thread.
+     *
+     * If the listener is added successfully, it will be called immediately with the current
+     * cross-window blur enabled state.
+     *
+     *
+     * @param listener the listener to be added. It will be called back with a boolean parameter,
+     *                 which is true if cross-window blur is enabled and false if it is disabled
+     *
+     * @see #removeCrossWindowBlurEnabledListener
+     * @see #isCrossWindowBlurEnabled
+     * @see LayoutParams#setBlurBehindRadius
+     * @see Window#setBackgroundBlurRadius
+     */
+    default void addCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) {
+    }
+
+    /**
+     * Removes a listener, previously added with {@link #addCrossWindowBlurEnabledListener}
+     *
+     * @param listener the listener to be removed
+     *
+     * @see #addCrossWindowBlurEnabledListener
+     */
+    default void removeCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) {
+    }
+
     public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
         /**
          * X position for this window.  With the default gravity it is ignored.
@@ -2722,6 +2782,15 @@
         public boolean hasManualSurfaceInsets;
 
         /**
+         * Whether we should use global insets state when report insets to the window. When set to
+         * {@code true}, all the insets will be reported to the window regardless of the z-order.
+         * Otherwise, only the insets above the given window will be reported.
+         *
+         * @hide
+         */
+        public boolean receiveInsetsIgnoringZOrder;
+
+        /**
          * Whether the previous surface insets should be used vs. what is currently set. When set
          * to {@code true}, the view root will ignore surfaces insets in this object and use what
          * it currently has.
@@ -3238,9 +3307,9 @@
          * The blur behind radius range starts at 0, which means no blur, and increases until 150
          * for the densest blur.
          *
-         * @see #FLAG_BLUR_BEHIND
+         * @see #setBlurBehindRadius
          */
-        public int blurBehindRadius = 0;
+        private int mBlurBehindRadius = 0;
 
         /**
          * The color mode requested by this window. The target display may
@@ -3534,6 +3603,50 @@
             return mColorMode;
         }
 
+        /**
+         * Blurs the screen behind the window. The effect is similar to that of {@link #dimAmount},
+         * but instead of dimmed, the content behind the window will be blurred (or combined with
+         * the dim amount, if such is specified).
+         *
+         * The density of the blur is set by the blur radius. The radius defines the size
+         * of the neighbouring area, from which pixels will be averaged to form the final
+         * color for each pixel. The operation approximates a Gaussian blur.
+         * A radius of 0 means no blur. The higher the radius, the denser the blur.
+         *
+         * Note the difference with {@link android.view.Window#setBackgroundBlurRadius},
+         * which blurs only within the bounds of the window. Blur behind blurs the whole screen
+         * behind the window.
+         *
+         * Requires {@link #FLAG_BLUR_BEHIND} to be set.
+         *
+         * Cross-window blur might not be supported by some devices due to GPU limitations. It can
+         * also be disabled at runtime, e.g. during battery saving mode, when multimedia tunneling
+         * is used or when minimal post processing is requested. In such situations, no blur will
+         * be computed or drawn, resulting in there being no depth separation between the window
+         * and the content behind it. To avoid this, the app might want to use more
+         * {@link #dimAmount} on its window. To listen for cross-window blur enabled/disabled
+         * events, use {@link #addCrossWindowBlurEnabledListener}.
+         *
+         * @param blurBehindRadius The blur radius to use for blur behind in pixels
+         *
+         * @see #FLAG_BLUR_BEHIND
+         * @see #getBlurBehindRadius
+         * @see WindowManager#addCrossWindowBlurEnabledListener
+         * @see Window#setBackgroundBlurRadius
+         */
+        public void setBlurBehindRadius(@IntRange(from = 0) int blurBehindRadius) {
+            mBlurBehindRadius = blurBehindRadius;
+        }
+
+        /**
+         * Returns the blur behind radius of the window.
+         *
+         * @see #setBlurBehindRadius
+         */
+        public int getBlurBehindRadius() {
+            return mBlurBehindRadius;
+        }
+
         /** @hide */
         @SystemApi
         public final void setUserActivityTimeout(long timeout) {
@@ -3610,15 +3723,16 @@
             out.writeInt(preferredDisplayModeId);
             out.writeInt(systemUiVisibility);
             out.writeInt(subtreeSystemUiVisibility);
-            out.writeInt(hasSystemUiListeners ? 1 : 0);
+            out.writeBoolean(hasSystemUiListeners);
             out.writeInt(inputFeatures);
             out.writeLong(userActivityTimeout);
             out.writeInt(surfaceInsets.left);
             out.writeInt(surfaceInsets.top);
             out.writeInt(surfaceInsets.right);
             out.writeInt(surfaceInsets.bottom);
-            out.writeInt(hasManualSurfaceInsets ? 1 : 0);
-            out.writeInt(preservePreviousSurfaceInsets ? 1 : 0);
+            out.writeBoolean(hasManualSurfaceInsets);
+            out.writeBoolean(receiveInsetsIgnoringZOrder);
+            out.writeBoolean(preservePreviousSurfaceInsets);
             out.writeLong(accessibilityIdOfAnchor);
             TextUtils.writeToParcel(accessibilityTitle, out, parcelableFlags);
             out.writeInt(mColorMode);
@@ -3629,7 +3743,7 @@
             out.writeInt(mFitInsetsSides);
             out.writeBoolean(mFitInsetsIgnoringVisibility);
             out.writeBoolean(preferMinimalPostProcessing);
-            out.writeInt(blurBehindRadius);
+            out.writeInt(mBlurBehindRadius);
             if (providesInsetsTypes != null) {
                 out.writeInt(providesInsetsTypes.length);
                 out.writeIntArray(providesInsetsTypes);
@@ -3679,15 +3793,16 @@
             preferredDisplayModeId = in.readInt();
             systemUiVisibility = in.readInt();
             subtreeSystemUiVisibility = in.readInt();
-            hasSystemUiListeners = in.readInt() != 0;
+            hasSystemUiListeners = in.readBoolean();
             inputFeatures = in.readInt();
             userActivityTimeout = in.readLong();
             surfaceInsets.left = in.readInt();
             surfaceInsets.top = in.readInt();
             surfaceInsets.right = in.readInt();
             surfaceInsets.bottom = in.readInt();
-            hasManualSurfaceInsets = in.readInt() != 0;
-            preservePreviousSurfaceInsets = in.readInt() != 0;
+            hasManualSurfaceInsets = in.readBoolean();
+            receiveInsetsIgnoringZOrder = in.readBoolean();
+            preservePreviousSurfaceInsets = in.readBoolean();
             accessibilityIdOfAnchor = in.readLong();
             accessibilityTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
             mColorMode = in.readInt();
@@ -3698,7 +3813,7 @@
             mFitInsetsSides = in.readInt();
             mFitInsetsIgnoringVisibility = in.readBoolean();
             preferMinimalPostProcessing = in.readBoolean();
-            blurBehindRadius = in.readInt();
+            mBlurBehindRadius = in.readInt();
             int insetsTypesLength = in.readInt();
             if (insetsTypesLength > 0) {
                 providesInsetsTypes = new int[insetsTypesLength];
@@ -3752,7 +3867,7 @@
         /** {@hide} */
         public static final int MINIMAL_POST_PROCESSING_PREFERENCE_CHANGED = 1 << 28;
         /** {@hide} */
-        public static final int BACKGROUND_BLUR_RADIUS_CHANGED = 1 << 29;
+        public static final int BLUR_BEHIND_RADIUS_CHANGED = 1 << 29;
 
         // internal buffer to backup/restore parameters under compatibility mode.
         private int[] mCompatibilityParamsBackup = null;
@@ -3916,6 +4031,11 @@
                 changes |= SURFACE_INSETS_CHANGED;
             }
 
+            if (receiveInsetsIgnoringZOrder != o.receiveInsetsIgnoringZOrder) {
+                receiveInsetsIgnoringZOrder = o.receiveInsetsIgnoringZOrder;
+                changes |= SURFACE_INSETS_CHANGED;
+            }
+
             if (preservePreviousSurfaceInsets != o.preservePreviousSurfaceInsets) {
                 preservePreviousSurfaceInsets = o.preservePreviousSurfaceInsets;
                 changes |= SURFACE_INSETS_CHANGED;
@@ -3943,9 +4063,9 @@
                 changes |= MINIMAL_POST_PROCESSING_PREFERENCE_CHANGED;
             }
 
-            if (blurBehindRadius != o.blurBehindRadius) {
-                blurBehindRadius = o.blurBehindRadius;
-                changes |= BACKGROUND_BLUR_RADIUS_CHANGED;
+            if (mBlurBehindRadius != o.mBlurBehindRadius) {
+                mBlurBehindRadius = o.mBlurBehindRadius;
+                changes |= BLUR_BEHIND_RADIUS_CHANGED;
             }
 
             // This can't change, it's only set at window creation time.
@@ -4104,6 +4224,9 @@
                     sb.append(" (!preservePreviousSurfaceInsets)");
                 }
             }
+            if (receiveInsetsIgnoringZOrder) {
+                sb.append(" receive insets ignoring z-order");
+            }
             if (mColorMode != COLOR_MODE_DEFAULT) {
                 sb.append(" colorMode=").append(ActivityInfo.colorModeToString(mColorMode));
             }
@@ -4111,9 +4234,9 @@
                 sb.append(" preferMinimalPostProcessing=");
                 sb.append(preferMinimalPostProcessing);
             }
-            if (blurBehindRadius != 0) {
+            if (mBlurBehindRadius != 0) {
                 sb.append(" blurBehindRadius=");
-                sb.append(blurBehindRadius);
+                sb.append(mBlurBehindRadius);
             }
             sb.append(System.lineSeparator());
             sb.append(prefix).append("  fl=").append(
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 23842b3..b398707 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -40,6 +40,7 @@
 import com.android.internal.os.IResultReceiver;
 
 import java.util.List;
+import java.util.function.Consumer;
 
 /**
  * Provides low-level communication with the system window manager for
@@ -301,4 +302,19 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    @Override
+    public boolean isCrossWindowBlurEnabled() {
+        return CrossWindowBlurListeners.getInstance().isCrossWindowBlurEnabled();
+    }
+
+    @Override
+    public void addCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) {
+        CrossWindowBlurListeners.getInstance().addListener(listener);
+    }
+
+    @Override
+    public void removeCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) {
+        CrossWindowBlurListeners.getInstance().removeListener(listener);
+    }
 }
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 97ce92c..ab46170 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -1781,8 +1781,12 @@
      * @param viewId The fully qualified resource name of the view id to find.
      * @return A list of node info.
      */
-    public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(String viewId) {
+    public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(@NonNull String viewId) {
         enforceSealed();
+        if (viewId == null) {
+            Log.e(TAG, "returns empty list due to null viewId.");
+            return Collections.emptyList();
+        }
         if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
             return Collections.emptyList();
         }
diff --git a/core/java/android/view/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java
index 9bf3626..9998fbc 100644
--- a/core/java/android/view/contentcapture/ContentCaptureContext.java
+++ b/core/java/android/view/contentcapture/ContentCaptureContext.java
@@ -22,6 +22,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.app.TaskInfo;
+import android.app.assist.ActivityId;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.LocusId;
@@ -36,6 +37,8 @@
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
 /**
  * Context associated with a {@link ContentCaptureSession} - see {@link ContentCaptureManager} for
  * more info.
@@ -99,16 +102,17 @@
 
     // Fields below are set by server when the session starts
     private final @Nullable ComponentName mComponentName;
-    private final int mTaskId;
     private final int mFlags;
     private final int mDisplayId;
+    private final ActivityId mActivityId;
 
     // Fields below are set by the service upon "delivery" and are not marshalled in the parcel
     private int mParentSessionId = NO_SESSION_ID;
 
     /** @hide */
     public ContentCaptureContext(@Nullable ContentCaptureContext clientContext,
-            @NonNull ComponentName componentName, int taskId, int displayId, int flags) {
+            @NonNull ActivityId activityId, @NonNull ComponentName componentName, int displayId,
+            int flags) {
         if (clientContext != null) {
             mHasClientContext = true;
             mExtras = clientContext.mExtras;
@@ -118,10 +122,10 @@
             mExtras = null;
             mId = null;
         }
-        mComponentName = Preconditions.checkNotNull(componentName);
-        mTaskId = taskId;
-        mDisplayId = displayId;
+        mComponentName = Objects.requireNonNull(componentName);
         mFlags = flags;
+        mDisplayId = displayId;
+        mActivityId = activityId;
     }
 
     private ContentCaptureContext(@NonNull Builder builder) {
@@ -130,8 +134,9 @@
         mId = builder.mId;
 
         mComponentName  = null;
-        mTaskId = mFlags = 0;
+        mFlags = 0;
         mDisplayId = Display.INVALID_DISPLAY;
+        mActivityId = null;
     }
 
     /** @hide */
@@ -140,9 +145,9 @@
         mExtras = original.mExtras;
         mId = original.mId;
         mComponentName = original.mComponentName;
-        mTaskId = original.mTaskId;
         mFlags = original.mFlags | extraFlags;
         mDisplayId = original.mDisplayId;
+        mActivityId = original.mActivityId;
     }
 
     /**
@@ -170,7 +175,7 @@
      */
     @SystemApi
     public int getTaskId() {
-        return mTaskId;
+        return mHasClientContext ? 0 : mActivityId.getTaskId();
     }
 
     /**
@@ -184,6 +189,18 @@
     }
 
     /**
+     * Gets the Activity id information associated with this context, or {@code null} when it is a
+     * child session.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public ActivityId getActivityId() {
+        return mHasClientContext ? null : mActivityId;
+    }
+
+    /**
      * Gets the id of the session that originated this session (through
      * {@link ContentCaptureSession#createContentCaptureSession(ContentCaptureContext)}),
      * or {@code null} if this is the main session associated with the Activity's {@link Context}.
@@ -309,7 +326,7 @@
         if (mId != null) {
             pw.print(", id="); mId.dump(pw);
         }
-        pw.print(", taskId="); pw.print(mTaskId);
+        pw.print(", activityId="); pw.print(mActivityId);
         pw.print(", displayId="); pw.print(mDisplayId);
         if (mParentSessionId != NO_SESSION_ID) {
             pw.print(", parentId="); pw.print(mParentSessionId);
@@ -333,7 +350,7 @@
 
         if (fromServer()) {
             builder.append("act=").append(ComponentName.flattenToShortString(mComponentName))
-                .append(", taskId=").append(mTaskId)
+                .append(", activityId=").append(mActivityId)
                 .append(", displayId=").append(mDisplayId)
                 .append(", flags=").append(mFlags);
         } else {
@@ -363,9 +380,9 @@
         }
         parcel.writeParcelable(mComponentName, flags);
         if (fromServer()) {
-            parcel.writeInt(mTaskId);
             parcel.writeInt(mDisplayId);
             parcel.writeInt(mFlags);
+            mActivityId.writeToParcel(parcel, flags);
         }
     }
 
@@ -393,11 +410,12 @@
                 // Client-state only
                 return clientContext;
             } else {
-                final int taskId = parcel.readInt();
                 final int displayId = parcel.readInt();
                 final int flags = parcel.readInt();
-                return new ContentCaptureContext(clientContext, componentName, taskId, displayId,
-                        flags);
+                final ActivityId activityId = new ActivityId(parcel);
+
+                return new ContentCaptureContext(clientContext, activityId, componentName,
+                        displayId, flags);
             }
         }
 
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 10f6c61..9523bcd 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -23,10 +23,13 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
 import android.annotation.UiThread;
+import android.annotation.UserIdInt;
+import android.app.Service;
 import android.content.ComponentName;
 import android.content.ContentCaptureOptions;
 import android.content.Context;
@@ -432,10 +435,11 @@
     /** @hide */
     @UiThread
     public void onActivityCreated(@NonNull IBinder applicationToken,
-            @NonNull ComponentName activityComponent) {
+            @NonNull IBinder shareableActivityToken, @NonNull ComponentName activityComponent) {
         if (mOptions.lite) return;
         synchronized (mLock) {
-            getMainContentCaptureSession().start(applicationToken, activityComponent, mFlags);
+            getMainContentCaptureSession().start(applicationToken, shareableActivityToken,
+                    activityComponent, mFlags);
         }
     }
 
@@ -755,6 +759,74 @@
         }
     }
 
+    /**
+     * Resets the temporary content capture service implementation to the default component.
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_CAPTURE)
+    public static void resetTemporaryService(@UserIdInt int userId) {
+        final IContentCaptureManager service = getService();
+        if (service == null) {
+            Log.e(TAG, "IContentCaptureManager is null");
+        }
+        try {
+            service.resetTemporaryService(userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Temporarily sets the content capture service implementation.
+     *
+     * @param userId user Id to set the temporary service on.
+     * @param serviceName name of the new component
+     * @param duration how long the change will be valid (the service will be automatically reset
+     * to the default component after this timeout expires).
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_CAPTURE)
+    public static void setTemporaryService(
+            @UserIdInt int userId, @NonNull String serviceName, int duration) {
+        final IContentCaptureManager service = getService();
+        if (service == null) {
+            Log.e(TAG, "IContentCaptureManager is null");
+        }
+        try {
+            service.setTemporaryService(userId, serviceName, duration);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Sets whether the default content capture service should be used.
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_CONTENT_CAPTURE)
+    public static void setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
+        final IContentCaptureManager service = getService();
+        if (service == null) {
+            Log.e(TAG, "IContentCaptureManager is null");
+        }
+        try {
+            service.setDefaultServiceEnabled(userId, enabled);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    private static IContentCaptureManager getService() {
+        return IContentCaptureManager.Stub.asInterface(ServiceManager.getService(
+                Service.CONTENT_CAPTURE_MANAGER_SERVICE));
+    }
+
     private interface MyRunnable {
         void run(@NonNull SyncResultReceiver receiver) throws RemoteException;
     }
diff --git a/core/java/android/view/contentcapture/IContentCaptureManager.aidl b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
index 01ead46..b1b443f 100644
--- a/core/java/android/view/contentcapture/IContentCaptureManager.aidl
+++ b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
@@ -44,8 +44,9 @@
      * @param flags Meta flags that enable or disable content capture (see
      *     {@link IContentCaptureContext#flags}).
      */
-    void startSession(IBinder activityToken, in ComponentName componentName,
-                      int sessionId, int flags, in IResultReceiver result);
+    void startSession(IBinder activityToken, IBinder shareableActivityToken,
+                      in ComponentName componentName, int sessionId, int flags,
+                      in IResultReceiver result);
 
     /**
      * Marks the end of a session for the calling user identified by
@@ -85,4 +86,19 @@
      * Returns a list with the ContentCaptureConditions for the package (or null if not defined).
      */
     void getContentCaptureConditions(String packageName, in IResultReceiver result);
+
+    /**
+     * Resets the temporary service implementation to the default component.
+     */
+    void resetTemporaryService(int userId);
+
+    /**
+     * Temporarily sets the service implementation.
+     */
+    void setTemporaryService(int userId, in String serviceName, int duration);
+
+    /**
+     * Sets whether the default service should be used.
+     */
+    void setDefaultServiceEnabled(int userId, boolean enabled);
 }
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 3c18b6b..5ca793e 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -123,6 +123,8 @@
 
     @Nullable
     private IBinder mApplicationToken;
+    @Nullable
+    private IBinder mShareableActivityToken;
 
     @Nullable
     private ComponentName mComponentName;
@@ -217,8 +219,8 @@
      * Starts this session.
      */
     @UiThread
-    void start(@NonNull IBinder token, @NonNull ComponentName component,
-            int flags) {
+    void start(@NonNull IBinder token, @NonNull IBinder shareableActivityToken,
+            @NonNull ComponentName component, int flags) {
         if (!isContentCaptureEnabled()) return;
 
         if (sVerbose) {
@@ -237,6 +239,7 @@
         }
         mState = STATE_WAITING_FOR_SERVER;
         mApplicationToken = token;
+        mShareableActivityToken = shareableActivityToken;
         mComponentName = component;
 
         if (sVerbose) {
@@ -245,8 +248,8 @@
         }
 
         try {
-            mSystemServerInterface.startSession(mApplicationToken, component, mId, flags,
-                    mSessionStateReceiver);
+            mSystemServerInterface.startSession(mApplicationToken, mShareableActivityToken,
+                    component, mId, flags, mSessionStateReceiver);
         } catch (RemoteException e) {
             Log.w(TAG, "Error starting session for " + component.flattenToShortString() + ": " + e);
         }
@@ -583,6 +586,7 @@
         mDisabled.set((newState & STATE_DISABLED) != 0);
         // TODO(b/122454205): must reset children (which currently is owned by superclass)
         mApplicationToken = null;
+        mShareableActivityToken = null;
         mComponentName = null;
         mEvents = null;
         if (mDirectServiceInterface != null) {
@@ -721,6 +725,10 @@
         if (mApplicationToken != null) {
             pw.print(prefix); pw.print("app token: "); pw.println(mApplicationToken);
         }
+        if (mShareableActivityToken != null) {
+            pw.print(prefix); pw.print("sharable activity token: ");
+            pw.println(mShareableActivityToken);
+        }
         if (mComponentName != null) {
             pw.print(prefix); pw.print("component name: ");
             pw.println(mComponentName.flattenToShortString());
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index 6ade5e6..de4554b 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -105,7 +105,7 @@
      */
     @MainThread
     default void initializeInternal(IBinder token, int displayId,
-            IInputMethodPrivilegedOperations privilegedOperations, int configChanges) {
+            IInputMethodPrivilegedOperations privilegedOperations) {
         updateInputMethodDisplay(displayId);
         attachToken(token);
     }
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 25712f8..5d876a6 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -18,23 +18,19 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
-import android.inputmethodservice.InputMethodService;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.AttributeSet;
@@ -64,7 +60,6 @@
  * @attr ref android.R.styleable#InputMethod_isDefault
  * @attr ref android.R.styleable#InputMethod_supportsSwitchingToNextInputMethod
  * @attr ref android.R.styleable#InputMethod_supportsInlineSuggestions
- * @attr ref android.R.styleable#InputMethod_configChanges
  */
 public final class InputMethodInfo implements Parcelable {
     static final String TAG = "InputMethodInfo";
@@ -123,12 +118,6 @@
     private final boolean mInlineSuggestionsEnabled;
 
     /**
-     * The flag for configurations IME assumes the responsibility for handling in
-     * {@link InputMethodService#onConfigurationChanged(Configuration)}}.
-     */
-    private final int mHandledConfigChanges;
-
-    /**
      * @param service the {@link ResolveInfo} corresponds in which the IME is implemented.
      * @return a unique ID to be returned by {@link #getId()}. We have used
      *         {@link ComponentName#flattenToShortString()} for this purpose (and it is already
@@ -214,8 +203,6 @@
                     false);
             inlineSuggestionsEnabled = sa.getBoolean(
                     com.android.internal.R.styleable.InputMethod_supportsInlineSuggestions, false);
-            mHandledConfigChanges = sa.getInt(
-                    com.android.internal.R.styleable.InputMethod_configChanges, 0);
             sa.recycle();
 
             final int depth = parser.getDepth();
@@ -300,7 +287,6 @@
         mIsVrOnly = source.readBoolean();
         mService = ResolveInfo.CREATOR.createFromParcel(source);
         mSubtypes = new InputMethodSubtypeArray(source);
-        mHandledConfigChanges = source.readInt();
         mForceDefault = false;
     }
 
@@ -312,22 +298,7 @@
         this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */,
                 settingsActivity, null /* subtypes */, 0 /* isDefaultResId */,
                 false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
-                false /* inlineSuggestionsEnabled */, false /* isVrOnly */,
-                0 /* handledConfigChanges */);
-    }
-
-    /**
-     * Temporary API for creating a built-in input method for test.
-     * @hide
-     */
-    @TestApi
-    public InputMethodInfo(@NonNull String packageName, @NonNull String className,
-            @NonNull CharSequence label, @NonNull String settingsActivity,
-            int handledConfigChanges) {
-        this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */,
-                settingsActivity, null /* subtypes */, 0 /* isDefaultResId */,
-                false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
-                false /* inlineSuggestionsEnabled */, false /* isVrOnly */, handledConfigChanges);
+                false /* inlineSuggestionsEnabled */, false /* isVrOnly */);
     }
 
     /**
@@ -339,7 +310,7 @@
             boolean forceDefault) {
         this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault,
                 true /* supportsSwitchingToNextInputMethod */, false /* inlineSuggestionsEnabled */,
-                false /* isVrOnly */, 0 /* handledconfigChanges */);
+                false /* isVrOnly */);
     }
 
     /**
@@ -350,8 +321,7 @@
             List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault,
             boolean supportsSwitchingToNextInputMethod, boolean isVrOnly) {
         this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault,
-                supportsSwitchingToNextInputMethod, false /* inlineSuggestionsEnabled */, isVrOnly,
-                0 /* handledConfigChanges */);
+                supportsSwitchingToNextInputMethod, false /* inlineSuggestionsEnabled */, isVrOnly);
     }
 
     /**
@@ -361,7 +331,7 @@
     public InputMethodInfo(ResolveInfo ri, boolean isAuxIme, String settingsActivity,
             List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault,
             boolean supportsSwitchingToNextInputMethod, boolean inlineSuggestionsEnabled,
-            boolean isVrOnly, int handledConfigChanges) {
+            boolean isVrOnly) {
         final ServiceInfo si = ri.serviceInfo;
         mService = ri;
         mId = new ComponentName(si.packageName, si.name).flattenToShortString();
@@ -373,7 +343,6 @@
         mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
         mInlineSuggestionsEnabled = inlineSuggestionsEnabled;
         mIsVrOnly = isVrOnly;
-        mHandledConfigChanges = handledConfigChanges;
     }
 
     private static ResolveInfo buildFakeResolveInfo(String packageName, String className,
@@ -520,17 +489,6 @@
         }
     }
 
-    /**
-     * Returns the bit mask of kinds of configuration changes that this IME
-     * can handle itself (without being restarted by the system).
-     *
-     * @attr ref android.R.styleable#InputMethod_configChanges
-     */
-    @ActivityInfo.Config
-    public int getConfigChanges() {
-        return mHandledConfigChanges;
-    }
-
     public void dump(Printer pw, String prefix) {
         pw.println(prefix + "mId=" + mId
                 + " mSettingsActivityName=" + mSettingsActivityName
@@ -621,7 +579,6 @@
         dest.writeBoolean(mIsVrOnly);
         mService.writeToParcel(dest, flags);
         mSubtypes.writeToParcel(dest);
-        dest.writeInt(mHandledConfigChanges);
     }
 
     /**
diff --git a/core/java/android/view/translation/ITranslationManager.aidl b/core/java/android/view/translation/ITranslationManager.aidl
index e175453..872e15e 100644
--- a/core/java/android/view/translation/ITranslationManager.aidl
+++ b/core/java/android/view/translation/ITranslationManager.aidl
@@ -36,6 +36,10 @@
          int sessionId, in IResultReceiver receiver, int userId);
 
     void updateUiTranslationState(int state, in TranslationSpec sourceSpec,
-         in TranslationSpec destSpec, in List<AutofillId> viewIds, in int taskId,
+         in TranslationSpec destSpec, in List<AutofillId> viewIds, IBinder token, int taskId,
+         int userId);
+    // deprecated
+    void updateUiTranslationStateByTaskId(int state, in TranslationSpec sourceSpec,
+         in TranslationSpec destSpec, in List<AutofillId> viewIds, int taskId,
          int userId);
 }
diff --git a/core/java/android/view/translation/TranslationSpec.java b/core/java/android/view/translation/TranslationSpec.java
index ab1bc47..16418a7 100644
--- a/core/java/android/view/translation/TranslationSpec.java
+++ b/core/java/android/view/translation/TranslationSpec.java
@@ -28,7 +28,7 @@
  * <p>This spec help specify information such as the language/locale for the translation, as well
  * as the data format for the translation (text, audio, etc.)</p>
  */
-@DataClass(genEqualsHashCode = true, genHiddenConstDefs = true)
+@DataClass(genEqualsHashCode = true, genHiddenConstDefs = true, genToString = true)
 public final class TranslationSpec implements Parcelable {
 
     /** Data format for translation is text. */
@@ -99,6 +99,18 @@
 
     @Override
     @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "TranslationSpec { " +
+                "language = " + mLanguage + ", " +
+                "dataFormat = " + mDataFormat +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
     public boolean equals(@android.annotation.Nullable Object o) {
         // You can override field equality logic by defining either of the methods like:
         // boolean fieldNameEquals(TranslationSpec other) { ... }
@@ -175,10 +187,10 @@
     };
 
     @DataClass.Generated(
-            time = 1609964630624L,
+            time = 1614326090637L,
             codegenVersion = "1.0.22",
             sourceFile = "frameworks/base/core/java/android/view/translation/TranslationSpec.java",
-            inputSignatures = "public static final  int DATA_FORMAT_TEXT\nprivate final @android.annotation.NonNull java.lang.String mLanguage\nprivate final @android.view.translation.TranslationSpec.DataFormat int mDataFormat\nclass TranslationSpec extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genHiddenConstDefs=true)")
+            inputSignatures = "public static final  int DATA_FORMAT_TEXT\nprivate final @android.annotation.NonNull java.lang.String mLanguage\nprivate final @android.view.translation.TranslationSpec.DataFormat int mDataFormat\nclass TranslationSpec extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genHiddenConstDefs=true, genToString=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/view/translation/Translator.java b/core/java/android/view/translation/Translator.java
index 22c3e57..163f832 100644
--- a/core/java/android/view/translation/Translator.java
+++ b/core/java/android/view/translation/Translator.java
@@ -35,6 +35,7 @@
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.util.SyncResultReceiver;
 
+import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
@@ -221,6 +222,12 @@
         return mId;
     }
 
+    /** @hide */
+    public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
+        pw.print(prefix); pw.print("sourceSpec: "); pw.println(mSourceSpec);
+        pw.print(prefix); pw.print("destSpec: "); pw.println(mDestSpec);
+    }
+
     /**
      * Requests a translation for the provided {@link TranslationRequest} using the Translator's
      * source spec and destination spec.
diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java
index b49d3c0..8100612 100644
--- a/core/java/android/view/translation/UiTranslationController.java
+++ b/core/java/android/view/translation/UiTranslationController.java
@@ -32,11 +32,15 @@
 import android.util.Log;
 import android.util.Pair;
 import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewRootImpl;
+import android.view.WindowManagerGlobal;
 import android.view.autofill.AutofillId;
 import android.view.translation.UiTranslationManager.UiTranslationState;
 
 import com.android.internal.util.function.pooled.PooledLambda;
 
+import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
@@ -130,6 +134,23 @@
     }
 
     /**
+     * Called to dump the translation information for Activity.
+     */
+    public void dump(String outerPrefix, PrintWriter pw) {
+        pw.print(outerPrefix); pw.println("UiTranslationController:");
+        final String pfx = outerPrefix + "  ";
+        pw.print(pfx); pw.print("activity: "); pw.println(mActivity);
+        final int translatorSize = mTranslators.size();
+        pw.print(outerPrefix); pw.print("number translator: "); pw.println(translatorSize);
+        for (int i = 0; i < translatorSize; i++) {
+            pw.print(outerPrefix); pw.print("#"); pw.println(i);
+            final Translator translator = mTranslators.valueAt(i);
+            translator.dump(outerPrefix, pw);
+            pw.println();
+        }
+    }
+
+    /**
      * The method is used by {@link Translator}, it will be called when the translation is done. The
      * translation result can be get from here.
      */
@@ -194,24 +215,19 @@
     private void onUiTranslationStarted(Translator translator, List<AutofillId> views) {
         synchronized (mLock) {
             // Find Views collect the translation data
-            // TODO(b/178084101): try to optimize, e.g. to this in a single traversal
-            final int viewCounts = views.size();
             final ArrayList<TranslationRequest> requests = new ArrayList<>();
-            for (int i = 0; i < viewCounts; i++) {
-                final AutofillId viewAutofillId = views.get(i);
-                final View view = mActivity.findViewByAutofillIdTraversal(viewAutofillId);
-                if (view == null) {
-                    Log.w(TAG, "Can not find the View for autofill id= " + viewAutofillId);
-                    continue;
-                }
-                mViews.put(viewAutofillId, new WeakReference<>(view));
+            final ArrayList<View> foundViews = new ArrayList<>();
+            findViewsTraversalByAutofillIds(views, foundViews);
+            for (int i = 0; i < foundViews.size(); i++) {
+                final View view = foundViews.get(i);
+                final int currentCount = i;
                 mActivity.runOnUiThread(() -> {
                     final TranslationRequest translationRequest = view.onCreateTranslationRequest();
                     if (translationRequest != null
                             && translationRequest.getTranslationText().length() > 0) {
                         requests.add(translationRequest);
                     }
-                    if (requests.size() == viewCounts) {
+                    if (currentCount == (foundViews.size() - 1)) {
                         Log.v(TAG, "onUiTranslationStarted: send " + requests.size() + " request.");
                         mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
                                 UiTranslationController::sendTranslationRequest,
@@ -222,6 +238,42 @@
         }
     }
 
+    private void findViewsTraversalByAutofillIds(List<AutofillId> sourceViewIds,
+            ArrayList<View> foundViews) {
+        final ArrayList<ViewRootImpl> roots =
+                WindowManagerGlobal.getInstance().getRootViews(mActivity.getActivityToken());
+        for (int rootNum = 0; rootNum < roots.size(); rootNum++) {
+            final View rootView = roots.get(rootNum).getView();
+            if (rootView instanceof ViewGroup) {
+                findViewsTraversalByAutofillIds((ViewGroup) rootView, sourceViewIds, foundViews);
+            } else {
+                addViewIfNeeded(sourceViewIds, rootView, foundViews);
+            }
+        }
+    }
+
+    private void findViewsTraversalByAutofillIds(ViewGroup viewGroup,
+            List<AutofillId> sourceViewIds, ArrayList<View> foundViews) {
+        final int childCount = viewGroup.getChildCount();
+        for (int i = 0; i < childCount; ++i) {
+            final View child = viewGroup.getChildAt(i);
+            if (child instanceof ViewGroup) {
+                findViewsTraversalByAutofillIds((ViewGroup) child, sourceViewIds, foundViews);
+            } else {
+                addViewIfNeeded(sourceViewIds, child, foundViews);
+            }
+        }
+    }
+
+    private void addViewIfNeeded(List<AutofillId> sourceViewIds, View view,
+            ArrayList<View> foundViews) {
+        final AutofillId autofillId = view.getAutofillId();
+        if (sourceViewIds.contains(autofillId)) {
+            mViews.put(autofillId, new WeakReference<>(view));
+            foundViews.add(view);
+        }
+    }
+
     private void runForEachView(Consumer<View> action) {
         synchronized (mLock) {
             final ArrayMap<AutofillId, WeakReference<View>> views = new ArrayMap<>(mViews);
diff --git a/core/java/android/view/translation/UiTranslationManager.java b/core/java/android/view/translation/UiTranslationManager.java
index eeb463a..a3a6a2e 100644
--- a/core/java/android/view/translation/UiTranslationManager.java
+++ b/core/java/android/view/translation/UiTranslationManager.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.app.assist.ActivityId;
 import android.content.Context;
 import android.os.RemoteException;
 import android.view.View;
@@ -95,26 +96,61 @@
     /**
      * Request ui translation for a given Views.
      *
+     * NOTE: Please use {@code startTranslation(TranslationSpec, TranslationSpec, List<AutofillId>,
+     * ActivityId)} instead.
+     *
      * @param sourceSpec {@link TranslationSpec} for the data to be translated.
      * @param destSpec {@link TranslationSpec} for the translated data.
      * @param viewIds A list of the {@link View}'s {@link AutofillId} which needs to be translated
      * @param taskId the Activity Task id which needs ui translation
      */
+    // TODO, hide the APIs
     @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
     public void startTranslation(@NonNull TranslationSpec sourceSpec,
             @NonNull TranslationSpec destSpec, @NonNull List<AutofillId> viewIds,
             int taskId) {
-        // TODO(b/177789967): Return result code or find a way to notify the status.
-        // TODO(b/177394471): The is a temparary API, the expected is requestUiTranslation(
-        //  TranslationSpec, TranslationSpec,List<AutofillId>, Binder). We may need more time to
-        //  implement it, use task id as initial version for demo.
         Objects.requireNonNull(sourceSpec);
         Objects.requireNonNull(destSpec);
         Objects.requireNonNull(viewIds);
+        if (viewIds.size() == 0) {
+            throw new IllegalArgumentException("Invalid empty views: " + viewIds);
+        }
+        try {
+            mService.updateUiTranslationStateByTaskId(STATE_UI_TRANSLATION_STARTED, sourceSpec,
+                    destSpec, viewIds, taskId, mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 
+    /**
+     * Request ui translation for a given Views.
+     *
+     * @param sourceSpec {@link TranslationSpec} for the data to be translated.
+     * @param destSpec {@link TranslationSpec} for the translated data.
+     * @param viewIds A list of the {@link View}'s {@link AutofillId} which needs to be translated
+     * @param activityId the identifier for the Activity which needs ui translation
+     * @throws IllegalArgumentException if the no {@link View}'s {@link AutofillId} in the list
+     * @throws NullPointerException the sourceSpec, destSpec, viewIds, activityId or
+     *         {@link android.app.assist.ActivityId#getToken()} is {@code null}
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
+    public void startTranslation(@NonNull TranslationSpec sourceSpec,
+            @NonNull TranslationSpec destSpec, @NonNull List<AutofillId> viewIds,
+            @NonNull ActivityId activityId) {
+        // TODO(b/177789967): Return result code or find a way to notify the status.
+        Objects.requireNonNull(sourceSpec);
+        Objects.requireNonNull(destSpec);
+        Objects.requireNonNull(viewIds);
+        Objects.requireNonNull(activityId);
+        Objects.requireNonNull(activityId.getToken());
+        if (viewIds.size() == 0) {
+            throw new IllegalArgumentException("Invalid empty views: " + viewIds);
+        }
         try {
             mService.updateUiTranslationState(STATE_UI_TRANSLATION_STARTED, sourceSpec,
-                    destSpec, viewIds, taskId, mContext.getUserId());
+                    destSpec, viewIds, activityId.getToken(), activityId.getTaskId(),
+                    mContext.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -124,14 +160,56 @@
      * Request to disable the ui translation. It will destroy all the {@link Translator}s and no
      * longer to show to show the translated text.
      *
+     * NOTE: Please use {@code finishTranslation(ActivityId)} instead.
+     *
      * @param taskId the Activity Task id which needs ui translation
      */
+    // TODO, hide the APIs
     @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
     public void finishTranslation(int taskId) {
         try {
-            // TODO(b/177394471): The is a temparary API, the expected is finishUiTranslation(
-            //  Binder). We may need more time to implement it, use task id as initial version.
+            mService.updateUiTranslationStateByTaskId(STATE_UI_TRANSLATION_FINISHED,
+                    null /* sourceSpec */, null /* destSpec*/, null /* viewIds */, taskId,
+                    mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Request to disable the ui translation. It will destroy all the {@link Translator}s and no
+     * longer to show to show the translated text.
+     *
+     * @param activityId the identifier for the Activity which needs ui translation
+     * @throws NullPointerException the activityId or
+     *         {@link android.app.assist.ActivityId#getToken()} is {@code null}
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
+    public void finishTranslation(@NonNull ActivityId activityId) {
+        try {
+            Objects.requireNonNull(activityId);
+            Objects.requireNonNull(activityId.getToken());
             mService.updateUiTranslationState(STATE_UI_TRANSLATION_FINISHED,
+                    null /* sourceSpec */, null /* destSpec*/, null /* viewIds */,
+                    activityId.getToken(), activityId.getTaskId(), mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Request to pause the current ui translation's {@link Translator} which will switch back to
+     * the original language.
+     *
+     * NOTE: Please use {@code pauseTranslation(ActivityId)} instead.
+     *
+     * @param taskId the Activity Task id which needs ui translation
+     */
+    // TODO, hide the APIs
+    @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
+    public void pauseTranslation(int taskId) {
+        try {
+            mService.updateUiTranslationStateByTaskId(STATE_UI_TRANSLATION_PAUSED,
                     null /* sourceSpec */, null /* destSpec*/, null /* viewIds */, taskId,
                     mContext.getUserId());
         } catch (RemoteException e) {
@@ -143,16 +221,18 @@
      * Request to pause the current ui translation's {@link Translator} which will switch back to
      * the original language.
      *
-     * @param taskId the Activity Task id which needs ui translation
+     * @param activityId the identifier for the Activity which needs ui translation
+     * @throws NullPointerException the activityId or
+     *         {@link android.app.assist.ActivityId#getToken()} is {@code null}
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
-    public void pauseTranslation(int taskId) {
+    public void pauseTranslation(@NonNull ActivityId activityId) {
         try {
-            // TODO(b/177394471): The is a temparary API, the expected is pauseUiTranslation(Binder)
-            // We may need more time to implement it, use task id as initial version for demo
+            Objects.requireNonNull(activityId);
+            Objects.requireNonNull(activityId.getToken());
             mService.updateUiTranslationState(STATE_UI_TRANSLATION_PAUSED,
-                    null /* sourceSpec */, null /* destSpec*/, null /* viewIds */, taskId,
-                    mContext.getUserId());
+                    null /* sourceSpec */, null /* destSpec*/, null /* viewIds */,
+                    activityId.getToken(), activityId.getTaskId(), mContext.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -162,18 +242,40 @@
      * Request to resume the paused ui translation's {@link Translator} which will switch to the
      * translated language if the text had been translated.
      *
+     * NOTE: Please use {@code resumeTranslation(ActivityId)} instead.
+     *
      * @param taskId the Activity Task id which needs ui translation
      */
+    // TODO, hide the APIs
     @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
     public void resumeTranslation(int taskId) {
         try {
-            // TODO(b/177394471): The is a temparary API, the expected is resumeUiTranslation(
-            //  Binder). We may need more time to implement it, use task id as initial version.
-            mService.updateUiTranslationState(STATE_UI_TRANSLATION_RESUMED,
+            mService.updateUiTranslationStateByTaskId(STATE_UI_TRANSLATION_RESUMED,
                     null /* sourceSpec */, null /* destSpec*/, null /* viewIds */,
                     taskId, mContext.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Request to resume the paused ui translation's {@link Translator} which will switch to the
+     * translated language if the text had been translated.
+     *
+     * @param activityId the identifier for the Activity which needs ui translation
+     * @throws NullPointerException the activityId or
+     *         {@link android.app.assist.ActivityId#getToken()} is {@code null}
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
+    public void resumeTranslation(@NonNull ActivityId activityId) {
+        try {
+            Objects.requireNonNull(activityId);
+            Objects.requireNonNull(activityId.getToken());
+            mService.updateUiTranslationState(STATE_UI_TRANSLATION_RESUMED,
+                    null /* sourceSpec */, null /* destSpec*/, null /* viewIds */,
+                    activityId.getToken(), activityId.getTaskId(), mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 5144717..2cf50bb 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -46,6 +46,8 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.content.res.loader.ResourcesLoader;
+import android.content.res.loader.ResourcesProvider;
 import android.graphics.Bitmap;
 import android.graphics.BlendMode;
 import android.graphics.Outline;
@@ -62,16 +64,19 @@
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
 import android.os.Process;
 import android.os.StrictMode;
 import android.os.UserHandle;
+import android.system.Os;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.DisplayMetrics;
 import android.util.IntArray;
 import android.util.Log;
 import android.util.Pair;
+import android.util.SparseIntArray;
 import android.util.TypedValue;
 import android.util.TypedValue.ComplexDimensionUnit;
 import android.view.ContextThemeWrapper;
@@ -92,6 +97,12 @@
 import com.android.internal.util.ContrastColorUtil;
 import com.android.internal.util.Preconditions;
 
+import java.io.ByteArrayOutputStream;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -520,8 +531,8 @@
      *  SUBCLASSES MUST BE IMMUTABLE SO CLONE WORKS!!!!!
      */
     private abstract static class Action implements Parcelable {
-        public abstract void apply(View root, ViewGroup rootParent,
-                InteractionHandler handler) throws ActionException;
+        public abstract void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                ColorResources colorResources) throws ActionException;
 
         public static final int MERGE_REPLACE = 0;
         public static final int MERGE_APPEND = 1;
@@ -551,8 +562,8 @@
          * and return the final action which will run on the UI thread.
          * Override this if some of the tasks can be performed async.
          */
-        public Action initActionAsync(
-                ViewTree root, ViewGroup rootParent, InteractionHandler handler) {
+        public Action initActionAsync(ViewTree root, ViewGroup rootParent,
+                InteractionHandler handler, ColorResources colorResources) {
             return this;
         }
 
@@ -595,7 +606,9 @@
     // Constant used during async execution. It is not parcelable.
     private static final Action ACTION_NOOP = new RuntimeAction() {
         @Override
-        public void apply(View root, ViewGroup rootParent, InteractionHandler handler) { }
+        public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                ColorResources colorResources) {
+        }
     };
 
     /**
@@ -692,6 +705,14 @@
         public String getPackageName() {
             return mContextForResources.getPackageName();
         }
+
+        @Override
+        public boolean isRestricted() {
+            // Override isRestricted and direct to resource's implementation. The isRestricted is
+            // used for determining the risky resources loading, e.g. fonts, thus direct to context
+            // for resource.
+            return mContextForResources.isRestricted();
+        }
     }
 
     private class SetEmptyView extends Action {
@@ -713,7 +734,8 @@
         }
 
         @Override
-        public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+        public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                ColorResources colorResources) {
             final View view = root.findViewById(viewId);
             if (!(view instanceof AdapterView<?>)) return;
 
@@ -748,7 +770,8 @@
         }
 
         @Override
-        public void apply(View root, ViewGroup rootParent, final InteractionHandler handler) {
+        public void apply(View root, ViewGroup rootParent, final InteractionHandler handler,
+                ColorResources colorResources) {
             final View target = root.findViewById(viewId);
             if (target == null) return;
 
@@ -820,7 +843,8 @@
         }
 
         @Override
-        public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+        public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                ColorResources colorResources) {
             final View target = root.findViewById(viewId);
             if (target == null) return;
 
@@ -843,7 +867,8 @@
                 if (a instanceof RemoteViewsListAdapter && viewTypeCount <= a.getViewTypeCount()) {
                     ((RemoteViewsListAdapter) a).setViewsList(list);
                 } else {
-                    v.setAdapter(new RemoteViewsListAdapter(v.getContext(), list, viewTypeCount));
+                    v.setAdapter(new RemoteViewsListAdapter(v.getContext(), list, viewTypeCount,
+                            colorResources));
                 }
             } else if (target instanceof AdapterViewAnimator) {
                 AdapterViewAnimator v = (AdapterViewAnimator) target;
@@ -851,7 +876,8 @@
                 if (a instanceof RemoteViewsListAdapter && viewTypeCount <= a.getViewTypeCount()) {
                     ((RemoteViewsListAdapter) a).setViewsList(list);
                 } else {
-                    v.setAdapter(new RemoteViewsListAdapter(v.getContext(), list, viewTypeCount));
+                    v.setAdapter(new RemoteViewsListAdapter(v.getContext(), list, viewTypeCount,
+                            colorResources));
                 }
             }
         }
@@ -882,7 +908,8 @@
         }
 
         @Override
-        public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+        public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                ColorResources colorResources) {
             final View target = root.findViewById(viewId);
             if (target == null) return;
 
@@ -919,7 +946,7 @@
 
         @Override
         public Action initActionAsync(ViewTree root, ViewGroup rootParent,
-                InteractionHandler handler) {
+                InteractionHandler handler, ColorResources colorResources) {
             SetRemoteViewsAdapterIntent copy = new SetRemoteViewsAdapterIntent(viewId, intent);
             copy.isAsync = true;
             return copy;
@@ -958,7 +985,8 @@
         }
 
         @Override
-        public void apply(View root, ViewGroup rootParent, final InteractionHandler handler) {
+        public void apply(View root, ViewGroup rootParent, final InteractionHandler handler,
+                ColorResources colorResources) {
             final View target = root.findViewById(viewId);
             if (target == null) return;
 
@@ -1037,7 +1065,8 @@
         }
 
         @Override
-        public void apply(View root, ViewGroup rootParent, final InteractionHandler handler) {
+        public void apply(View root, ViewGroup rootParent, final InteractionHandler handler,
+                ColorResources colorResources) {
             final View target = root.findViewById(viewId);
             if (target == null) return;
             if (!(target instanceof CompoundButton)) {
@@ -1240,7 +1269,8 @@
         }
 
         @Override
-        public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+        public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                ColorResources colorResources) {
             final View target = root.findViewById(viewId);
             if (target == null) return;
 
@@ -1297,7 +1327,8 @@
         }
 
         @Override
-        public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+        public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                ColorResources colorResources) {
             final View target = root.findViewById(viewId);
             if (target == null) return;
 
@@ -1334,7 +1365,8 @@
         }
 
         @Override
-        public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+        public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                ColorResources colorResources) {
             final View view = root.findViewById(viewId);
             if (view == null) return;
 
@@ -1437,12 +1469,12 @@
         }
 
         @Override
-        public void apply(View root, ViewGroup rootParent,
-                InteractionHandler handler) throws ActionException {
+        public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                ColorResources colorResources) throws ActionException {
             ReflectionAction ra = new ReflectionAction(viewId, methodName,
                     BaseReflectionAction.BITMAP,
                     bitmap);
-            ra.apply(root, rootParent, handler);
+            ra.apply(root, rootParent, handler, colorResources);
         }
 
         @Override
@@ -1518,7 +1550,8 @@
         protected abstract Object getParameterValue(@Nullable View view) throws ActionException;
 
         @Override
-        public final void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+        public final void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                ColorResources colorResources) {
             final View view = root.findViewById(viewId);
             if (view == null) return;
 
@@ -1536,7 +1569,7 @@
 
         @Override
         public final Action initActionAsync(ViewTree root, ViewGroup rootParent,
-                InteractionHandler handler) {
+                InteractionHandler handler, ColorResources colorResources) {
             final View view = root.findViewById(viewId);
             if (view == null) return ACTION_NOOP;
 
@@ -1938,7 +1971,8 @@
         }
 
         @Override
-        public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+        public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                ColorResources colorResources) {
             mRunnable.run();
         }
     }
@@ -1993,7 +2027,8 @@
         }
 
         @Override
-        public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+        public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                ColorResources colorResources) {
             final Context context = root.getContext();
             final ViewGroup target = root.findViewById(viewId);
 
@@ -2002,12 +2037,14 @@
             }
 
             // Inflate nested views and add as children
-            target.addView(mNestedViews.apply(context, target, handler), mIndex);
+            target.addView(
+                    mNestedViews.apply(context, target, handler, null /* size */, colorResources),
+                    mIndex);
         }
 
         @Override
         public Action initActionAsync(ViewTree root, ViewGroup rootParent,
-                InteractionHandler handler) {
+                InteractionHandler handler, ColorResources colorResources) {
             // In the async implementation, update the view tree so that subsequent calls to
             // findViewById return the current view.
             root.createTree();
@@ -2019,8 +2056,8 @@
 
             // Inflate nested views and perform all the async tasks for the child remoteView.
             final Context context = root.mRoot.getContext();
-            final AsyncApplyTask task = mNestedViews.getAsyncApplyTask(
-                    context, targetVg, null, handler);
+            final AsyncApplyTask task = mNestedViews.getAsyncApplyTask(context, targetVg,
+                    null /* listener */, handler, null /* size */, colorResources);
             final ViewTree tree = task.doInBackground();
 
             if (tree == null) {
@@ -2033,8 +2070,8 @@
 
             return new RuntimeAction() {
                 @Override
-                public void apply(View root, ViewGroup rootParent, InteractionHandler handler)
-                        throws ActionException {
+                public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                        ColorResources colorResources) throws ActionException {
                     task.onPostExecute(tree);
                     targetVg.addView(task.mResult, mIndex);
                 }
@@ -2095,7 +2132,8 @@
         }
 
         @Override
-        public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+        public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                ColorResources colorResources) {
             final ViewGroup target = root.findViewById(viewId);
 
             if (target == null) {
@@ -2112,7 +2150,7 @@
 
         @Override
         public Action initActionAsync(ViewTree root, ViewGroup rootParent,
-                InteractionHandler handler) {
+                InteractionHandler handler, ColorResources colorResources) {
             // In the async implementation, update the view tree so that subsequent calls to
             // findViewById return the current view.
             root.createTree();
@@ -2136,8 +2174,8 @@
             }
             return new RuntimeAction() {
                 @Override
-                public void apply(View root, ViewGroup rootParent, InteractionHandler handler)
-                        throws ActionException {
+                public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                        ColorResources colorResources) throws ActionException {
                     if (mViewIdToKeep == REMOVE_ALL_VIEWS_ID) {
                         targetVg.removeAllViews();
                         return;
@@ -2192,7 +2230,8 @@
         }
 
         @Override
-        public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+        public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                ColorResources colorResources) {
             final View target = root.findViewById(viewId);
 
             if (target == null || target == root) {
@@ -2207,7 +2246,7 @@
 
         @Override
         public Action initActionAsync(ViewTree root, ViewGroup rootParent,
-                InteractionHandler handler) {
+                InteractionHandler handler, ColorResources colorResources) {
             // In the async implementation, update the view tree so that subsequent calls to
             // findViewById return the correct view.
             root.createTree();
@@ -2226,8 +2265,8 @@
             parent.mChildren.remove(target);
             return new RuntimeAction() {
                 @Override
-                public void apply(View root, ViewGroup rootParent, InteractionHandler handler)
-                        throws ActionException {
+                public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                        ColorResources colorResources) throws ActionException {
                     parentVg.removeView(target.mRoot);
                 }
             };
@@ -2306,7 +2345,8 @@
         }
 
         @Override
-        public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+        public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                ColorResources colorResources) {
             final TextView target = root.findViewById(viewId);
             if (target == null) return;
             if (drawablesLoaded) {
@@ -2337,7 +2377,7 @@
 
         @Override
         public Action initActionAsync(ViewTree root, ViewGroup rootParent,
-                InteractionHandler handler) {
+                InteractionHandler handler, ColorResources colorResources) {
             final TextView target = root.findViewById(viewId);
             if (target == null) return ACTION_NOOP;
 
@@ -2415,7 +2455,8 @@
         }
 
         @Override
-        public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+        public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                ColorResources colorResources) {
             final TextView target = root.findViewById(viewId);
             if (target == null) return;
             target.setTextSize(units, size);
@@ -2460,7 +2501,8 @@
         }
 
         @Override
-        public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+        public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                ColorResources colorResources) {
             final View target = root.findViewById(viewId);
             if (target == null) return;
             target.setPadding(left, top, right, bottom);
@@ -2533,7 +2575,8 @@
         }
 
         @Override
-        public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+        public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                ColorResources colorResources) {
             final View target = root.findViewById(viewId);
             if (target == null) {
                 return;
@@ -2646,7 +2689,8 @@
         }
 
         @Override
-        public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+        public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                ColorResources colorResources) {
             final View target = root.findViewById(viewId);
             if (target == null) return;
 
@@ -2681,7 +2725,8 @@
         }
 
         @Override
-        public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+        public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                ColorResources colorResources) {
             // Let's traverse the viewtree and override all textColors!
             Stack<View> viewsToProcess = new Stack<>();
             viewsToProcess.add(root);
@@ -2731,7 +2776,8 @@
         }
 
         @Override
-        public void apply(View root, ViewGroup rootParent, InteractionHandler handler) {
+        public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                ColorResources colorResources) {
             final View target = root.findViewById(mViewId);
             if (target == null) return;
 
@@ -2765,7 +2811,8 @@
         }
 
         @Override
-        public void apply(View root, ViewGroup rootParent, InteractionHandler handler)
+        public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                ColorResources colorResources)
                 throws ActionException {
             final View target = root.findViewById(viewId);
             if (target == null) return;
@@ -2816,8 +2863,8 @@
         }
 
         @Override
-        public void apply(View root, ViewGroup rootParent, InteractionHandler handler)
-                throws ActionException {
+        public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                ColorResources colorResources) throws ActionException {
             final View target = root.findViewById(viewId);
             if (target == null) return;
 
@@ -2893,8 +2940,8 @@
         }
 
         @Override
-        public void apply(View root, ViewGroup rootParent, InteractionHandler handler)
-                throws ActionException {
+        public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
+                ColorResources colorResources) throws ActionException {
             final View target = root.findViewById(viewId);
             if (target == null) return;
 
@@ -4662,7 +4709,7 @@
         RemoteViews rvToApply = getRemoteViewsToApply(context, size);
 
         View result = inflateView(context, rvToApply, parent);
-        rvToApply.performApply(result, parent, handler);
+        rvToApply.performApply(result, parent, handler, null);
         return result;
     }
 
@@ -4674,27 +4721,39 @@
 
     /** @hide */
     public View applyWithTheme(@NonNull Context context, @NonNull ViewGroup parent,
-            @Nullable InteractionHandler handler,
-            @StyleRes int applyThemeResId,
+            @Nullable InteractionHandler handler, @StyleRes int applyThemeResId,
             @Nullable PointF size) {
         RemoteViews rvToApply = getRemoteViewsToApply(context, size);
 
-        View result = inflateView(context, rvToApply, parent, applyThemeResId);
-        rvToApply.performApply(result, parent, handler);
+        View result = inflateView(context, rvToApply, parent, applyThemeResId, null);
+        rvToApply.performApply(result, parent, handler, null);
+        return result;
+    }
+
+    /** @hide */
+    public View apply(Context context, ViewGroup parent, InteractionHandler handler,
+            @NonNull PointF size, @Nullable ColorResources colorResources) {
+        RemoteViews rvToApply = getRemoteViewsToApply(context, size);
+
+        View result = inflateView(context, rvToApply, parent, 0, colorResources);
+        rvToApply.performApply(result, parent, handler, colorResources);
         return result;
     }
 
     private View inflateView(Context context, RemoteViews rv, ViewGroup parent) {
-        return inflateView(context, rv, parent, 0);
+        return inflateView(context, rv, parent, 0, null);
     }
 
     private View inflateView(Context context, RemoteViews rv, ViewGroup parent,
-            @StyleRes int applyThemeResId) {
+            @StyleRes int applyThemeResId, @Nullable ColorResources colorResources) {
         // RemoteViews may be built by an application installed in another
         // user. So build a context that loads resources from that user but
         // still returns the current users userId so settings like data / time formats
         // are loaded without requiring cross user persmissions.
         final Context contextForResources = getContextForResources(context);
+        if (colorResources != null) {
+            colorResources.apply(contextForResources);
+        }
         Context inflationContext = new RemoteViewsContextWrapper(context, contextForResources);
 
         // If mApplyThemeResId is not given, Theme.DeviceDefault will be used.
@@ -4756,34 +4815,37 @@
      */
     public CancellationSignal applyAsync(
             Context context, ViewGroup parent, Executor executor, OnViewAppliedListener listener) {
-        return applyAsync(context, parent, executor, listener, null);
+        return applyAsync(context, parent, executor, listener, null /* handler */);
     }
 
 
     /** @hide */
     public CancellationSignal applyAsync(Context context, ViewGroup parent,
             Executor executor, OnViewAppliedListener listener, InteractionHandler handler) {
-        return applyAsync(context, parent, executor, listener, handler, null);
+        return applyAsync(context, parent, executor, listener, handler, null /* size */);
     }
 
     /** @hide */
     public CancellationSignal applyAsync(Context context, ViewGroup parent,
             Executor executor, OnViewAppliedListener listener, InteractionHandler handler,
             PointF size) {
-        return getAsyncApplyTask(context, parent, listener, handler, size).startTaskOnExecutor(
-                executor);
+        return getAsyncApplyTask(context, parent, listener, handler, size, null /* themeColors */)
+                .startTaskOnExecutor(executor);
+    }
+
+    /** @hide */
+    public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor,
+            OnViewAppliedListener listener, InteractionHandler handler, PointF size,
+            ColorResources colorResources) {
+        return getAsyncApplyTask(context, parent, listener, handler, size, colorResources)
+                .startTaskOnExecutor(executor);
     }
 
     private AsyncApplyTask getAsyncApplyTask(Context context, ViewGroup parent,
-            OnViewAppliedListener listener, InteractionHandler handler) {
-        return getAsyncApplyTask(context, parent, listener, handler, null);
-    }
-
-    private AsyncApplyTask getAsyncApplyTask(Context context, ViewGroup parent,
-            OnViewAppliedListener listener, InteractionHandler handler, PointF size) {
-        return new AsyncApplyTask(getRemoteViewsToApply(context, size), parent, context,
-                listener,
-                handler, null);
+            OnViewAppliedListener listener, InteractionHandler handler, PointF size,
+            ColorResources colorResources) {
+        return new AsyncApplyTask(getRemoteViewsToApply(context, size), parent, context, listener,
+                handler, colorResources, null /* result */);
     }
 
     private class AsyncApplyTask extends AsyncTask<Void, Void, ViewTree>
@@ -4794,6 +4856,7 @@
         final Context mContext;
         final OnViewAppliedListener mListener;
         final InteractionHandler mHandler;
+        final ColorResources mColorResources;
 
         private View mResult;
         private ViewTree mTree;
@@ -4802,11 +4865,12 @@
 
         private AsyncApplyTask(
                 RemoteViews rv, ViewGroup parent, Context context, OnViewAppliedListener listener,
-                InteractionHandler handler, View result) {
+                InteractionHandler handler, ColorResources colorResources, View result) {
             mRV = rv;
             mParent = parent;
             mContext = context;
             mListener = listener;
+            mColorResources = colorResources;
             mHandler = handler;
 
             mResult = result;
@@ -4816,7 +4880,7 @@
         protected ViewTree doInBackground(Void... params) {
             try {
                 if (mResult == null) {
-                    mResult = inflateView(mContext, mRV, mParent);
+                    mResult = inflateView(mContext, mRV, mParent, 0, mColorResources);
                 }
 
                 mTree = new ViewTree(mResult);
@@ -4825,7 +4889,8 @@
                     mActions = new Action[count];
                     for (int i = 0; i < count && !isCancelled(); i++) {
                         // TODO: check if isCancelled in nested views.
-                        mActions[i] = mRV.mActions.get(i).initActionAsync(mTree, mParent, mHandler);
+                        mActions[i] = mRV.mActions.get(i).initActionAsync(mTree, mParent, mHandler,
+                                mColorResources);
                     }
                 } else {
                     mActions = null;
@@ -4850,7 +4915,7 @@
                         InteractionHandler handler = mHandler == null
                                 ? DEFAULT_INTERACTION_HANDLER : mHandler;
                         for (Action a : mActions) {
-                            a.apply(viewTree.mRoot, mParent, handler);
+                            a.apply(viewTree.mRoot, mParent, handler, mColorResources);
                         }
                     }
                 } catch (Exception e) {
@@ -4894,16 +4959,17 @@
      * the {@link #apply(Context,ViewGroup)} call.
      */
     public void reapply(Context context, View v) {
-        reapply(context, v, null, null);
+        reapply(context, v, null /* handler */);
     }
 
     /** @hide */
     public void reapply(Context context, View v, InteractionHandler handler) {
-        reapply(context, v, handler, null);
+        reapply(context, v, handler, null /* size */, null /* colorResources */);
     }
 
     /** @hide */
-    public void reapply(Context context, View v, InteractionHandler handler, PointF size) {
+    public void reapply(Context context, View v, InteractionHandler handler, PointF size,
+            ColorResources colorResources) {
         RemoteViews rvToApply = getRemoteViewsToApply(context, size);
 
         // In the case that a view has this RemoteViews applied in one orientation or size, is
@@ -4917,7 +4983,7 @@
             }
         }
 
-        rvToApply.performApply(v, (ViewGroup) v.getParent(), handler);
+        rvToApply.performApply(v, (ViewGroup) v.getParent(), handler, colorResources);
     }
 
     /**
@@ -4933,20 +4999,21 @@
      * @return CancellationSignal
      * @hide
      */
-    public CancellationSignal reapplyAsync(
-            Context context, View v, Executor executor, OnViewAppliedListener listener) {
-        return reapplyAsync(context, v, executor, listener, null, null);
+    public CancellationSignal reapplyAsync(Context context, View v, Executor executor,
+            OnViewAppliedListener listener) {
+        return reapplyAsync(context, v, executor, listener, null);
     }
 
     /** @hide */
     public CancellationSignal reapplyAsync(Context context, View v, Executor executor,
             OnViewAppliedListener listener, InteractionHandler handler) {
-        return reapplyAsync(context, v, executor, listener, handler, null);
+        return reapplyAsync(context, v, executor, listener, handler, null, null);
     }
 
     /** @hide */
     public CancellationSignal reapplyAsync(Context context, View v, Executor executor,
-            OnViewAppliedListener listener, InteractionHandler handler, PointF size) {
+            OnViewAppliedListener listener, InteractionHandler handler, PointF size,
+            ColorResources colorResources) {
         RemoteViews rvToApply = getRemoteViewsToApply(context, size);
 
         // In the case that a view has this RemoteViews applied in one orientation, is persisted
@@ -4960,16 +5027,18 @@
         }
 
         return new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(),
-                context, listener, handler, v).startTaskOnExecutor(executor);
+                context, listener, handler, colorResources, v).startTaskOnExecutor(
+                executor);
     }
 
-    private void performApply(View v, ViewGroup parent, InteractionHandler handler) {
+    private void performApply(View v, ViewGroup parent, InteractionHandler handler,
+            ColorResources colorResources) {
         if (mActions != null) {
             handler = handler == null ? DEFAULT_INTERACTION_HANDLER : handler;
             final int count = mActions.size();
             for (int i = 0; i < count; i++) {
                 Action a = mActions.get(i);
-                a.apply(v, parent, handler);
+                a.apply(v, parent, handler, colorResources);
             }
         }
     }
@@ -5010,6 +5079,122 @@
     }
 
     /**
+     * Object allowing the modification of a context to overload the system's dynamic colors.
+     *
+     * Only colors from {@link android.R.color#system_primary_0} to
+     * {@link android.R.color#system_neutral_1000} can be overloaded.
+     * @hide
+     */
+    public static final class ColorResources {
+        // Set of valid colors resources.
+        private static final int FIRST_RESOURCE_COLOR_ID = android.R.color.system_primary_0;
+        private static final int LAST_RESOURCE_COLOR_ID = android.R.color.system_neutral_1000;
+        // Size, in bytes, of an entry in the array of colors in an ARSC file.
+        private static final int ARSC_ENTRY_SIZE = 16;
+
+        private ResourcesLoader mLoader;
+
+        private ColorResources(ResourcesLoader loader) {
+            mLoader = loader;
+        }
+
+        /**
+         * Apply the color resources to the given context.
+         *
+         * No resource resolution must have be done on the context given to that method.
+         */
+        public void apply(Context context) {
+            context.getResources().addLoaders(mLoader);
+        }
+
+        private static ByteArrayOutputStream readFileContent(InputStream input) throws IOException {
+            ByteArrayOutputStream content = new ByteArrayOutputStream(2048);
+            byte[] buffer = new byte[4096];
+            while (input.available() > 0) {
+                int read = input.read(buffer);
+                content.write(buffer, 0, read);
+            }
+            return content;
+        }
+
+        /**
+         * Creates the compiled resources content from the asset stored in the APK.
+         *
+         * The asset is a compiled resource with the correct resources name and correct ids, only
+         * the values are incorrect. The last value is at the very end of the file. The resources
+         * are in an array, the array's entries are 16 bytes each. We use this to work out the
+         * location of all the positions of the various resources.
+         */
+        private static byte[] createCompiledResourcesContent(Context context,
+                SparseIntArray colorResources) throws IOException {
+            byte[] content;
+            try (InputStream input = context.getResources().openRawResource(
+                    com.android.internal.R.raw.remote_views_color_resources)) {
+                ByteArrayOutputStream rawContent = readFileContent(input);
+                content = rawContent.toByteArray();
+            }
+            int valuesOffset =
+                    content.length - (LAST_RESOURCE_COLOR_ID & 0xffff) * ARSC_ENTRY_SIZE - 4;
+            if (valuesOffset < 0) {
+                Log.e(LOG_TAG, "ARSC file for theme colors is invalid.");
+                return null;
+            }
+            for (int colorRes = FIRST_RESOURCE_COLOR_ID; colorRes <= LAST_RESOURCE_COLOR_ID;
+                    colorRes++) {
+                // The last 2 bytes are the index in the color array.
+                int index = colorRes & 0xffff;
+                int offset = valuesOffset + index * ARSC_ENTRY_SIZE;
+                int value = colorResources.get(colorRes, context.getColor(colorRes));
+                // Write the 32 bit integer in little endian
+                for (int b = 0; b < 4; b++) {
+                    content[offset + b] = (byte) (value & 0xff);
+                    value >>= 8;
+                }
+            }
+            return content;
+        }
+
+        /**
+         *  Adds a resource loader for theme colors to the given context.
+         *
+         * @param context Context of the view hosting the widget.
+         * @param colorMapping Mapping of resources to color values.
+         *
+         * @hide
+         */
+        public static ColorResources create(Context context, SparseIntArray colorMapping) {
+            try {
+                byte[] contentBytes = createCompiledResourcesContent(context, colorMapping);
+                if (contentBytes == null) {
+                    return null;
+                }
+                FileDescriptor arscFile = null;
+                try {
+                    arscFile = Os.memfd_create("remote_views_theme_colors.arsc", 0 /* flags */);
+                    // Note: This must not be closed through the OutputStream.
+                    try (OutputStream pipeWriter = new FileOutputStream(arscFile)) {
+                        pipeWriter.write(contentBytes);
+
+                        try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(arscFile)) {
+                            ResourcesLoader colorsLoader = new ResourcesLoader();
+                            colorsLoader.addProvider(ResourcesProvider
+                                    .loadFromTable(pfd, null /* assetsProvider */));
+                            return new ColorResources(colorsLoader);
+                        }
+                    }
+                } finally {
+                    if (arscFile != null) {
+                        Os.close(arscFile);
+                    }
+                }
+            } catch (Exception ex) {
+                Log.e(LOG_TAG, "Failed to setup the context for theme colors", ex);
+            }
+            return null;
+        }
+    }
+
+    /**
      * Returns the number of actions in this RemoteViews. Can be used as a sequence number.
      *
      * @hide
diff --git a/core/java/android/widget/RemoteViewsListAdapter.java b/core/java/android/widget/RemoteViewsListAdapter.java
index b80fe48..827d033 100644
--- a/core/java/android/widget/RemoteViewsListAdapter.java
+++ b/core/java/android/widget/RemoteViewsListAdapter.java
@@ -31,12 +31,14 @@
     private ArrayList<RemoteViews> mRemoteViewsList;
     private ArrayList<Integer> mViewTypes = new ArrayList<Integer>();
     private int mViewTypeCount;
+    private RemoteViews.ColorResources mColorResources;
 
     public RemoteViewsListAdapter(Context context, ArrayList<RemoteViews> remoteViews,
-            int viewTypeCount) {
+            int viewTypeCount, RemoteViews.ColorResources colorResources) {
         mContext = context;
         mRemoteViewsList = remoteViews;
         mViewTypeCount = viewTypeCount;
+        mColorResources = colorResources;
         init();
     }
 
@@ -90,9 +92,10 @@
             if (convertView != null && rv != null &&
                     convertView.getId() == rv.getLayoutId()) {
                 v = convertView;
-                rv.reapply(mContext, v);
+                rv.reapply(mContext, v, null /* handler */, null /* size */, mColorResources);
             } else {
-                v = rv.apply(mContext, parent);
+                v = rv.apply(mContext, parent, null /* handler */, null /* size */,
+                        mColorResources);
             }
             return v;
         } else {
diff --git a/core/java/android/window/ClientWindowFrames.java b/core/java/android/window/ClientWindowFrames.java
index e22a5eb..acf9882 100644
--- a/core/java/android/window/ClientWindowFrames.java
+++ b/core/java/android/window/ClientWindowFrames.java
@@ -58,9 +58,9 @@
 
     /** Needed for AIDL out parameters. */
     public void readFromParcel(Parcel in) {
-        frame.set(Rect.CREATOR.createFromParcel(in));
-        displayFrame.set(Rect.CREATOR.createFromParcel(in));
-        backdropFrame.set(Rect.CREATOR.createFromParcel(in));
+        frame.readFromParcel(in);
+        displayFrame.readFromParcel(in);
+        backdropFrame.readFromParcel(in);
     }
 
     @Override
diff --git a/core/java/android/window/StartingWindowInfo.java b/core/java/android/window/StartingWindowInfo.java
index 63b9e9b..d1c1e40 100644
--- a/core/java/android/window/StartingWindowInfo.java
+++ b/core/java/android/window/StartingWindowInfo.java
@@ -35,6 +35,31 @@
 @TestApi
 public final class StartingWindowInfo implements Parcelable {
     /**
+     * Prefer nothing or not care the type of starting window.
+     * @hide
+     */
+    public static final int STARTING_WINDOW_TYPE_NONE = 0;
+    /**
+     * Prefer splash screen starting window.
+     * @hide
+     */
+    public static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 1;
+    /**
+     * Prefer snapshot starting window.
+     * @hide
+     */
+    public static final int STARTING_WINDOW_TYPE_SNAPSHOT = 2;
+    /**
+     * @hide
+     */
+    @IntDef(flag = true, prefix = "STARTING_WINDOW_TYPE_", value = {
+            STARTING_WINDOW_TYPE_NONE,
+            STARTING_WINDOW_TYPE_SPLASH_SCREEN,
+            STARTING_WINDOW_TYPE_SNAPSHOT
+    })
+    public @interface StartingWindowType {}
+
+    /**
      * The {@link TaskInfo} from this task.
      *  @hide
      */
diff --git a/core/java/android/window/TaskSnapshot.java b/core/java/android/window/TaskSnapshot.java
index dc07e44..f1e5fb9 100644
--- a/core/java/android/window/TaskSnapshot.java
+++ b/core/java/android/window/TaskSnapshot.java
@@ -46,7 +46,7 @@
     private final int mOrientation;
     /** See {@link android.view.Surface.Rotation} */
     @Surface.Rotation
-    private int mRotation;
+    private final int mRotation;
     /** The size of the snapshot before scaling */
     private final Point mTaskSize;
     private final Rect mContentInsets;
@@ -90,15 +90,15 @@
     private TaskSnapshot(Parcel source) {
         mId = source.readLong();
         mTopActivityComponent = ComponentName.readFromParcel(source);
-        mSnapshot = source.readParcelable(null /* classLoader */);
+        mSnapshot = source.readTypedObject(HardwareBuffer.CREATOR);
         int colorSpaceId = source.readInt();
         mColorSpace = colorSpaceId >= 0 && colorSpaceId < ColorSpace.Named.values().length
                 ? ColorSpace.get(ColorSpace.Named.values()[colorSpaceId])
                 : ColorSpace.get(ColorSpace.Named.SRGB);
         mOrientation = source.readInt();
         mRotation = source.readInt();
-        mTaskSize = source.readParcelable(null /* classLoader */);
-        mContentInsets = source.readParcelable(null /* classLoader */);
+        mTaskSize = source.readTypedObject(Point.CREATOR);
+        mContentInsets = source.readTypedObject(Rect.CREATOR);
         mIsLowResolution = source.readBoolean();
         mIsRealSnapshot = source.readBoolean();
         mWindowingMode = source.readInt();
@@ -235,13 +235,12 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeLong(mId);
         ComponentName.writeToParcel(mTopActivityComponent, dest);
-        dest.writeParcelable(mSnapshot != null && !mSnapshot.isClosed() ? mSnapshot : null,
-                0);
+        dest.writeTypedObject(mSnapshot != null && !mSnapshot.isClosed() ? mSnapshot : null, 0);
         dest.writeInt(mColorSpace.getId());
         dest.writeInt(mOrientation);
         dest.writeInt(mRotation);
-        dest.writeParcelable(mTaskSize, 0);
-        dest.writeParcelable(mContentInsets, 0);
+        dest.writeTypedObject(mTaskSize, 0);
+        dest.writeTypedObject(mContentInsets, 0);
         dest.writeBoolean(mIsLowResolution);
         dest.writeBoolean(mIsRealSnapshot);
         dest.writeInt(mWindowingMode);
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 3a9f3b9..eecd0cf 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -74,11 +74,11 @@
     @UnsupportedAppUsage
     List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, in int[] ops);
     void getHistoricalOps(int uid, String packageName, String attributionTag, in List<String> ops,
-            int filter, long beginTimeMillis, long endTimeMillis, int flags,
+            int historyFlags, int filter, long beginTimeMillis, long endTimeMillis, int flags,
             in RemoteCallback callback);
     void getHistoricalOpsFromDiskRaw(int uid, String packageName, String attributionTag,
-            in List<String> ops, int filter, long beginTimeMillis, long endTimeMillis, int flags,
-            in RemoteCallback callback);
+            in List<String> ops, int historyFlags, int filter, long beginTimeMillis,
+            long endTimeMillis, int flags, in RemoteCallback callback);
     void offsetHistory(long duration);
     void setHistoryParameters(int mode, long baseSnapshotInterval, int compressionStep);
     void addHistoricalOps(in AppOpsManager.HistoricalOps ops);
diff --git a/core/java/com/android/internal/graphics/drawable/BackgroundBlurDrawable.java b/core/java/com/android/internal/graphics/drawable/BackgroundBlurDrawable.java
index 96dac56..402d7fe 100644
--- a/core/java/com/android/internal/graphics/drawable/BackgroundBlurDrawable.java
+++ b/core/java/com/android/internal/graphics/drawable/BackgroundBlurDrawable.java
@@ -19,6 +19,7 @@
 import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UiThread;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -31,12 +32,14 @@
 import android.graphics.Rect;
 import android.graphics.RenderNode;
 import android.graphics.drawable.Drawable;
-import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Log;
-import android.view.SurfaceControl;
+import android.util.LongSparseArray;
 import android.view.ViewRootImpl;
 
 import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 
 /**
  * A drawable that keeps track of a blur region, pokes a hole under it, and propagates its state
@@ -52,26 +55,40 @@
     private final Paint mPaint = new Paint();
     private final Path mRectPath = new Path();
     private final float[] mTmpRadii = new float[8];
-    private final SurfaceControl.BlurRegion mBlurRegion = new SurfaceControl.BlurRegion();
 
-    // This will be called from a thread pool.
-    private final RenderNode.PositionUpdateListener mPositionUpdateListener =
+    private boolean mVisible = true;
+
+    // Confined to UiThread. The values are copied into a BlurRegion, which lives on
+    // RenderThread to avoid interference with UiThread updates.
+    private int mBlurRadius;
+    private float mCornerRadiusTL;
+    private float mCornerRadiusTR;
+    private float mCornerRadiusBL;
+    private float mCornerRadiusBR;
+    private float mAlpha = 1;
+
+    // Do not update from UiThread. This holds the latest position for this drawable. It is used
+    // by the Aggregator from RenderThread to get the final position of the blur region sent to SF
+    private final Rect mRect = new Rect();
+    // This is called from a thread pool. The callbacks might come out of order w.r.t. the frame
+    // number, so we send a Runnable holding the actual update to the Aggregator. The Aggregator
+    // can apply the update on RenderThread when processing that same frame.
+    @VisibleForTesting
+    public final RenderNode.PositionUpdateListener mPositionUpdateListener =
             new RenderNode.PositionUpdateListener() {
             @Override
             public void positionChanged(long frameNumber, int left, int top, int right,
                     int bottom) {
-                synchronized (mAggregator) {
-                    mBlurRegion.rect.set(left, top, right, bottom);
-                    mAggregator.onBlurRegionUpdated(BackgroundBlurDrawable.this, mBlurRegion);
-                }
+                mAggregator.onRenderNodePositionChanged(frameNumber, () -> {
+                    mRect.set(left, top, right, bottom);
+                });
             }
 
             @Override
             public void positionLost(long frameNumber) {
-                synchronized (mAggregator) {
-                    mBlurRegion.rect.setEmpty();
-                    mAggregator.onBlurRegionUpdated(BackgroundBlurDrawable.this, mBlurRegion);
-                }
+                mAggregator.onRenderNodePositionChanged(frameNumber, () -> {
+                    mRect.setEmpty();
+                });
             }
         };
 
@@ -79,6 +96,7 @@
         mAggregator = aggregator;
         mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
         mPaint.setColor(Color.TRANSPARENT);
+        mPaint.setAntiAlias(true);
         mRenderNode = new RenderNode("BackgroundBlurDrawable");
         mRenderNode.addPositionUpdateListener(mPositionUpdateListener);
     }
@@ -104,23 +122,30 @@
     public boolean setVisible(boolean visible, boolean restart) {
         boolean changed = super.setVisible(visible, restart);
         if (changed) {
-            mBlurRegion.visible = visible;
+            mVisible = visible;
+            mAggregator.onBlurDrawableUpdated(this);
         }
         return changed;
     }
 
     @Override
     public void setAlpha(int alpha) {
-        mBlurRegion.alpha = alpha / 255f;
-        invalidateSelf();
+        if (mAlpha != alpha / 255f) {
+            mAlpha = alpha / 255f;
+            invalidateSelf();
+            mAggregator.onBlurDrawableUpdated(this);
+        }
     }
 
     /**
      * Blur radius in pixels.
      */
     public void setBlurRadius(int blurRadius) {
-        mBlurRegion.blurRadius = blurRadius;
-        invalidateSelf();
+        if (mBlurRadius != blurRadius) {
+            mBlurRadius = blurRadius;
+            invalidateSelf();
+            mAggregator.onBlurDrawableUpdated(this);
+        }
     }
 
     /**
@@ -139,14 +164,18 @@
      */
     public void setCornerRadius(float cornerRadiusTL, float cornerRadiusTR, float cornerRadiusBL,
             float cornerRadiusBR) {
-        synchronized (mAggregator) {
-            mBlurRegion.cornerRadiusTL = cornerRadiusTL;
-            mBlurRegion.cornerRadiusTR = cornerRadiusTR;
-            mBlurRegion.cornerRadiusBL = cornerRadiusBL;
-            mBlurRegion.cornerRadiusBR = cornerRadiusBR;
+        if (mCornerRadiusTL != cornerRadiusTL
+                || mCornerRadiusTR != cornerRadiusTR
+                || mCornerRadiusBL != cornerRadiusBL
+                || mCornerRadiusBR != cornerRadiusBR) {
+            mCornerRadiusTL = cornerRadiusTL;
+            mCornerRadiusTR = cornerRadiusTR;
+            mCornerRadiusBL = cornerRadiusBL;
+            mCornerRadiusBR = cornerRadiusBR;
+            updatePath();
+            invalidateSelf();
+            mAggregator.onBlurDrawableUpdated(this);
         }
-        updatePath();
-        invalidateSelf();
     }
 
     @Override
@@ -157,12 +186,10 @@
     }
 
     private void updatePath() {
-        synchronized (mAggregator) {
-            mTmpRadii[0] = mTmpRadii[1] = mBlurRegion.cornerRadiusTL;
-            mTmpRadii[2] = mTmpRadii[3] = mBlurRegion.cornerRadiusTR;
-            mTmpRadii[4] = mTmpRadii[5] = mBlurRegion.cornerRadiusBL;
-            mTmpRadii[6] = mTmpRadii[7] = mBlurRegion.cornerRadiusBR;
-        }
+        mTmpRadii[0] = mTmpRadii[1] = mCornerRadiusTL;
+        mTmpRadii[2] = mTmpRadii[3] = mCornerRadiusTR;
+        mTmpRadii[4] = mTmpRadii[5] = mCornerRadiusBL;
+        mTmpRadii[6] = mTmpRadii[7] = mCornerRadiusBR;
         mRectPath.reset();
         if (getAlpha() == 0 || !isVisible()) {
             return;
@@ -182,17 +209,32 @@
         return PixelFormat.TRANSLUCENT;
     }
 
+    @Override
+    public String toString() {
+        return "BackgroundBlurDrawable{"
+            + "blurRadius=" + mBlurRadius
+            + ", corners={" + mCornerRadiusTL
+            + "," + mCornerRadiusTR
+            + "," + mCornerRadiusBL
+            + "," + mCornerRadiusBR
+            + "}, alpha=" + mAlpha
+            + ", visible=" + mVisible
+            + "}";
+    }
+
     /**
      * Responsible for keeping track of all blur regions of a {@link ViewRootImpl} and posting a
      * message when it's time to propagate them.
      */
     public static final class Aggregator {
-
-        private final ArrayMap<BackgroundBlurDrawable, SurfaceControl.BlurRegion> mBlurRegions =
-                new ArrayMap<>();
+        private final Object mRtLock = new Object();
+        // Maintains a list of all *visible* blur drawables. Confined to  UI thread
+        private final ArraySet<BackgroundBlurDrawable> mDrawables = new ArraySet();
+        @GuardedBy("mRtLock")
+        private final LongSparseArray<ArraySet<Runnable>> mFrameRtUpdates = new LongSparseArray();
         private final ViewRootImpl mViewRoot;
-        private float[][] mTmpBlurRegionsArray;
-        private boolean mNeedsUpdate;
+        private BlurRegion[] mTmpBlurRegionsForFrame = new BlurRegion[0];
+        private boolean mHasUiUpdates;
 
         public Aggregator(ViewRootImpl viewRoot) {
             mViewRoot = viewRoot;
@@ -209,60 +251,191 @@
         }
 
         /**
-         * Called from RenderThread only, already locked.
-         * @param drawable
-         * @param blurRegion
+         * Called when a BackgroundBlurDrawable has been updated
          */
-        void onBlurRegionUpdated(BackgroundBlurDrawable drawable,
-                SurfaceControl.BlurRegion blurRegion) {
-            if (blurRegion.rect.isEmpty() || blurRegion.alpha == 0 || blurRegion.blurRadius == 0
-                    || !blurRegion.visible) {
-                mBlurRegions.remove(drawable);
-                mNeedsUpdate = true;
-                if (DEBUG) {
-                    Log.d(TAG, "Remove " + blurRegion);
+        @UiThread
+        void onBlurDrawableUpdated(BackgroundBlurDrawable drawable) {
+            final boolean shouldBeDrawn =
+                    drawable.mAlpha != 0 && drawable.mBlurRadius > 0 && drawable.mVisible;
+            final boolean isDrawn = mDrawables.contains(drawable);
+            if (shouldBeDrawn) {
+                mHasUiUpdates = true;
+                if (!isDrawn) {
+                    mDrawables.add(drawable);
+                    if (DEBUG) {
+                        Log.d(TAG, "Add " + drawable);
+                    }
+                } else {
+                    if (DEBUG) {
+                        Log.d(TAG, "Update " + drawable);
+                    }
                 }
-            } else {
-                mBlurRegions.put(drawable, blurRegion);
-                mNeedsUpdate = true;
+            } else if (!shouldBeDrawn && isDrawn) {
+                mHasUiUpdates = true;
+                mDrawables.remove(drawable);
                 if (DEBUG) {
-                    Log.d(TAG, "Update " + blurRegion);
+                    Log.d(TAG, "Remove " + drawable);
                 }
             }
         }
 
+        // Called from a thread pool
+        void onRenderNodePositionChanged(long frameNumber, Runnable update) {
+            // One of the blur region's position has changed, so we have to send an updated list
+            // of blur regions to SurfaceFlinger for this frame.
+            synchronized (mRtLock) {
+                ArraySet<Runnable> frameRtUpdates = mFrameRtUpdates.get(frameNumber);
+                if (frameRtUpdates == null) {
+                    frameRtUpdates = new ArraySet<>();
+                    mFrameRtUpdates.put(frameNumber, frameRtUpdates);
+                }
+                frameRtUpdates.add(update);
+            }
+        }
+
         /**
-         * If there are any blur regions visible on the screen at the moment.
+         * @return true if there are any updates that need to be sent to SF
          */
+        @UiThread
+        public boolean hasUpdates() {
+            return mHasUiUpdates;
+        }
+
+        /**
+         * @return true if there are any visible blur regions
+         */
+        @UiThread
         public boolean hasRegions() {
-            return mBlurRegions.size() > 0;
+            return mDrawables.size() > 0;
         }
 
         /**
-         * Dispatch blur updates, if there were any.
-         * @param frameNumber Frame where the update should happen.
+         * @return an array of BlurRegions, which are holding a copy of the information in
+         *         all the currently visible BackgroundBlurDrawables
          */
-        public void dispatchBlurTransactionIfNeeded(long frameNumber) {
-            synchronized (this) {
-                if (!mNeedsUpdate) {
-                    return;
+        @UiThread
+        public BlurRegion[] getBlurRegionsCopyForRT() {
+            if (mHasUiUpdates) {
+                mTmpBlurRegionsForFrame = new BlurRegion[mDrawables.size()];
+                for (int i = 0; i < mDrawables.size(); i++) {
+                    mTmpBlurRegionsForFrame[i] = new BlurRegion(mDrawables.valueAt(i));
                 }
-                mNeedsUpdate = false;
-
-                if (mTmpBlurRegionsArray == null
-                        || mTmpBlurRegionsArray.length != mBlurRegions.size()) {
-                    mTmpBlurRegionsArray = new float[mBlurRegions.size()][];
-                }
-                if (DEBUG) {
-                    Log.d(TAG, "onBlurRegionUpdated will dispatch " + mTmpBlurRegionsArray.length
-                            + " regions for frame " + frameNumber);
-                }
-                for (int i = 0; i < mTmpBlurRegionsArray.length; i++) {
-                    mTmpBlurRegionsArray[i] = mBlurRegions.valueAt(i).toFloatArray();
-                }
-
-                mViewRoot.dispatchBlurRegions(mTmpBlurRegionsArray, frameNumber);
+                mHasUiUpdates = false;
             }
+
+            return mTmpBlurRegionsForFrame;
+        }
+
+        /**
+         * Called on RenderThread.
+         *
+         * @return all blur regions if there are any ui or position updates for this frame,
+         *         null otherwise
+         */
+        @VisibleForTesting
+        public float[][] getBlurRegionsToDispatchToSf(long frameNumber,
+                BlurRegion[] blurRegionsForFrame, boolean hasUiUpdatesForFrame) {
+            synchronized (mRtLock) {
+                if (!hasUiUpdatesForFrame && (mFrameRtUpdates.size() == 0
+                            || mFrameRtUpdates.keyAt(0) > frameNumber)) {
+                    return null;
+                }
+
+                // mFrameRtUpdates holds position updates coming from a thread pool span from
+                // RenderThread. At this point, all position updates for frame frameNumber should
+                // have been added to mFrameRtUpdates.
+                // Here, we apply all updates for frames <= frameNumber in case some previous update
+                // has been missed. This also protects mFrameRtUpdates from memory leaks.
+                while (mFrameRtUpdates.size() != 0 && mFrameRtUpdates.keyAt(0) <= frameNumber) {
+                    final ArraySet<Runnable> frameUpdates = mFrameRtUpdates.valueAt(0);
+                    mFrameRtUpdates.removeAt(0);
+                    for (int i = 0; i < frameUpdates.size(); i++) {
+                        frameUpdates.valueAt(i).run();
+                    }
+                }
+            }
+
+            if (DEBUG) {
+                Log.d(TAG, "Dispatching " + blurRegionsForFrame.length + " blur regions:");
+            }
+
+            final float[][] blurRegionsArray = new float[blurRegionsForFrame.length][];
+            for (int i = 0; i < blurRegionsArray.length; i++) {
+                blurRegionsArray[i] = blurRegionsForFrame[i].toFloatArray();
+                if (DEBUG) {
+                    Log.d(TAG, blurRegionsForFrame[i].toString());
+                }
+            }
+            return blurRegionsArray;
+        }
+
+        /**
+         * Called on RenderThread in FrameDrawingCallback.
+         * Dispatch all blur regions if there are any ui or position updates.
+         */
+        public void dispatchBlurTransactionIfNeeded(long frameNumber,
+                BlurRegion[] blurRegionsForFrame, boolean hasUiUpdatesForFrame) {
+            final float[][] blurRegionsArray = getBlurRegionsToDispatchToSf(frameNumber,
+                    blurRegionsForFrame, hasUiUpdatesForFrame);
+            if (blurRegionsArray != null) {
+                mViewRoot.dispatchBlurRegions(blurRegionsArray, frameNumber);
+            }
+        }
+
+    }
+
+    /**
+     * Wrapper for sending blur data to SurfaceFlinger
+     * Confined to RenderThread.
+     */
+    public static final class BlurRegion {
+        public final int blurRadius;
+        public final float cornerRadiusTL;
+        public final float cornerRadiusTR;
+        public final float cornerRadiusBL;
+        public final float cornerRadiusBR;
+        public final float alpha;
+        public final Rect rect;
+
+        BlurRegion(BackgroundBlurDrawable drawable) {
+            alpha = drawable.mAlpha;
+            blurRadius = drawable.mBlurRadius;
+            cornerRadiusTL = drawable.mCornerRadiusTL;
+            cornerRadiusTR = drawable.mCornerRadiusTR;
+            cornerRadiusBL = drawable.mCornerRadiusBL;
+            cornerRadiusBR = drawable.mCornerRadiusBR;
+            rect = drawable.mRect;
+        }
+
+        /**
+         * Serializes this class into a float array that's more JNI friendly.
+         */
+        float[] toFloatArray() {
+            final float[] floatArray = new float[10];
+            floatArray[0] = blurRadius;
+            floatArray[1] = alpha;
+            floatArray[2] = rect.left;
+            floatArray[3] = rect.top;
+            floatArray[4] = rect.right;
+            floatArray[5] = rect.bottom;
+            floatArray[6] = cornerRadiusTL;
+            floatArray[7] = cornerRadiusTR;
+            floatArray[8] = cornerRadiusBL;
+            floatArray[9] = cornerRadiusBR;
+            return floatArray;
+        }
+
+        @Override
+        public String toString() {
+            return "BlurRegion{"
+                    + "blurRadius=" + blurRadius
+                    + ", corners={" + cornerRadiusTL
+                    + "," + cornerRadiusTR
+                    + "," + cornerRadiusBL
+                    + "," + cornerRadiusBR
+                    + "}, alpha=" + alpha
+                    + ", rect=" + rect
+                    + "}";
         }
     }
 }
diff --git a/core/java/com/android/internal/graphics/palette/CelebiQuantizer.java b/core/java/com/android/internal/graphics/palette/CelebiQuantizer.java
new file mode 100644
index 0000000..de6bf20
--- /dev/null
+++ b/core/java/com/android/internal/graphics/palette/CelebiQuantizer.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.internal.graphics.palette;
+
+import java.util.List;
+
+/**
+ * An implementation of Celebi's WSM quantizer, or, a Kmeans quantizer that starts with centroids
+ * from a Wu quantizer to ensure 100% reproducible and quality results, and has some optimizations
+ * to the Kmeans algorithm.
+ *
+ * See Celebi 2011, “Improving the Performance of K-Means for Color Quantization”
+ */
+public class CelebiQuantizer implements Quantizer {
+    private List<Palette.Swatch> mSwatches;
+
+    public CelebiQuantizer() { }
+
+    @Override
+    public void quantize(int[] pixels, int maxColors) {
+        WuQuantizer wu = new WuQuantizer(pixels, maxColors);
+        wu.quantize(pixels, maxColors);
+        List<Palette.Swatch> wuSwatches = wu.getQuantizedColors();
+        LABCentroid labCentroidProvider = new LABCentroid();
+        WSMeansQuantizer kmeans =
+                new WSMeansQuantizer(WSMeansQuantizer.createStartingCentroids(labCentroidProvider,
+                        wuSwatches), labCentroidProvider, pixels, maxColors);
+        kmeans.quantize(pixels, maxColors);
+        mSwatches = kmeans.getQuantizedColors();
+    }
+
+    @Override
+    public List<Palette.Swatch> getQuantizedColors() {
+        return mSwatches;
+    }
+}
diff --git a/core/java/com/android/internal/graphics/palette/CentroidProvider.java b/core/java/com/android/internal/graphics/palette/CentroidProvider.java
new file mode 100644
index 0000000..5fcfcba
--- /dev/null
+++ b/core/java/com/android/internal/graphics/palette/CentroidProvider.java
@@ -0,0 +1,38 @@
+/*
+ * 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.graphics.palette;
+
+import android.annotation.ColorInt;
+
+interface CentroidProvider {
+    /**
+     * @return 3 dimensions representing the color
+     */
+    float[] getCentroid(@ColorInt int color);
+
+    /**
+     * @param centroid 3 dimensions representing the color
+     * @return 32-bit ARGB representation
+     */
+    @ColorInt
+    int getColor(float[] centroid);
+
+    /**
+     * Distance between two centroids.
+     */
+    float distance(float[] a, float[] b);
+}
diff --git a/core/java/com/android/internal/graphics/palette/ColorCutQuantizer.java b/core/java/com/android/internal/graphics/palette/ColorCutQuantizer.java
index 9ac753b..7779494 100644
--- a/core/java/com/android/internal/graphics/palette/ColorCutQuantizer.java
+++ b/core/java/com/android/internal/graphics/palette/ColorCutQuantizer.java
@@ -35,6 +35,8 @@
 import android.graphics.Color;
 import android.util.TimingLogger;
 
+import com.android.internal.graphics.palette.Palette.Swatch;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -42,9 +44,6 @@
 import java.util.List;
 import java.util.PriorityQueue;
 
-import com.android.internal.graphics.ColorUtils;
-import com.android.internal.graphics.palette.Palette.Swatch;
-
 /**
  * Copied from: frameworks/support/v7/palette/src/main/java/android/support/v7/
  * graphics/ColorCutQuantizer.java
@@ -77,20 +76,17 @@
     int[] mHistogram;
     List<Swatch> mQuantizedColors;
     TimingLogger mTimingLogger;
-    Palette.Filter[] mFilters;
 
     private final float[] mTempHsl = new float[3];
 
     /**
      * Execute color quantization.
      *
-     * @param pixels histogram representing an image's pixel data
+     * @param pixels    histogram representing an image's pixel data
      * @param maxColors The maximum number of colors that should be in the result palette.
-     * @param filters Set of filters to use in the quantization stage
      */
-    public void quantize(final int[] pixels, final int maxColors, final Palette.Filter[] filters) {
+    public void quantize(final int[] pixels, final int maxColors) {
         mTimingLogger = LOG_TIMINGS ? new TimingLogger(LOG_TAG, "Creation") : null;
-        mFilters = filters;
 
         final int[] hist = mHistogram = new int[1 << (QUANTIZE_WORD_WIDTH * 3)];
         for (int i = 0; i < pixels.length; i++) {
@@ -108,10 +104,6 @@
         // Now let's count the number of distinct colors
         int distinctColorCount = 0;
         for (int color = 0; color < hist.length; color++) {
-            if (hist[color] > 0 && shouldIgnoreColor(color)) {
-                // If we should ignore the color, set the population to 0
-                hist[color] = 0;
-            }
             if (hist[color] > 0) {
                 // If the color has population, increase the distinct color count
                 distinctColorCount++;
@@ -186,7 +178,7 @@
      * and splitting them. Once split, the new box and the remaining box are offered back to the
      * queue.
      *
-     * @param queue {@link java.util.PriorityQueue} to poll for boxes
+     * @param queue   {@link java.util.PriorityQueue} to poll for boxes
      * @param maxSize Maximum amount of boxes to split
      */
     private void splitBoxes(final PriorityQueue<Vbox> queue, final int maxSize) {
@@ -216,11 +208,7 @@
         ArrayList<Swatch> colors = new ArrayList<>(vboxes.size());
         for (Vbox vbox : vboxes) {
             Swatch swatch = vbox.getAverageColor();
-            if (!shouldIgnoreColor(swatch)) {
-                // As we're averaging a color box, we can still get colors which we do not want, so
-                // we check again here
-                colors.add(swatch);
-            }
+            colors.add(swatch);
         }
         return colors;
     }
@@ -230,7 +218,7 @@
      */
     private class Vbox {
         // lower and upper index are inclusive
-        private int mLowerIndex;
+        private final int mLowerIndex;
         private int mUpperIndex;
         // Population of colors within this box
         private int mPopulation;
@@ -373,7 +361,7 @@
             modifySignificantOctet(colors, longestDimension, mLowerIndex, mUpperIndex);
 
             final int midPoint = mPopulation / 2;
-            for (int i = mLowerIndex, count = 0; i <= mUpperIndex; i++)  {
+            for (int i = mLowerIndex, count = 0; i <= mUpperIndex; i++) {
                 count += hist[colors[i]];
                 if (count >= midPoint) {
                     // we never want to split on the upperIndex, as this will result in the same
@@ -447,27 +435,6 @@
         }
     }
 
-    private boolean shouldIgnoreColor(int color565) {
-        final int rgb = approximateToRgb888(color565);
-        ColorUtils.colorToHSL(rgb, mTempHsl);
-        return shouldIgnoreColor(rgb, mTempHsl);
-    }
-
-    private boolean shouldIgnoreColor(Swatch color) {
-        return shouldIgnoreColor(color.getRgb(), color.getHsl());
-    }
-
-    private boolean shouldIgnoreColor(int rgb, float[] hsl) {
-        if (mFilters != null && mFilters.length > 0) {
-            for (int i = 0, count = mFilters.length; i < count; i++) {
-                if (!mFilters[i].isAllowed(rgb, hsl)) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
     /**
      * Comparator which sorts {@link Vbox} instances based on their volume, in descending order
      */
@@ -498,7 +465,8 @@
     }
 
     private static int approximateToRgb888(int color) {
-        return approximateToRgb888(quantizedRed(color), quantizedGreen(color), quantizedBlue(color));
+        return approximateToRgb888(quantizedRed(color), quantizedGreen(color),
+                quantizedBlue(color));
     }
 
     /**
diff --git a/core/java/com/android/internal/graphics/palette/Contrast.java b/core/java/com/android/internal/graphics/palette/Contrast.java
new file mode 100644
index 0000000..3dd1b8d
--- /dev/null
+++ b/core/java/com/android/internal/graphics/palette/Contrast.java
@@ -0,0 +1,103 @@
+/*
+ * 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.graphics.palette;
+
+/**
+ * Helper methods for determining contrast between two colors, either via the colors themselves
+ * or components in different color spaces.
+ */
+public class Contrast {
+    /**
+     *
+     * @param y Y in XYZ that contrasts with the returned Y value
+     * @param contrast contrast ratio between color argument and returned Y value. Must be >= 1
+     *    or an exception will be thrown
+     * @return the lower Y coordinate in XYZ space that contrasts with color, or -1 if reaching
+     *    no Y coordinate reaches contrast with color.
+     */
+    public static float lighterY(float y, float contrast) {
+        assert (contrast >= 1);
+        float answer = -5 + contrast * (5 + y);
+        if (answer > 100.0) {
+            return -1;
+        }
+        return answer;
+    }
+
+
+    /**
+     * @param y Y in XYZ that contrasts with the returned Y value
+     * @param contrast contrast ratio between color argument and returned Y value. Must be >= 1
+     *    or an exception will be thrown
+     * @return the lower Y coordinate in XYZ space that contrasts with color, or -1 if reaching
+     *    no Y coordinate reaches contrast with color.
+     */
+    public static float darkerY(float y, float contrast) {
+        assert (contrast >= 1);
+        float answer = (5 - 5 * contrast + y) / contrast;
+        if (answer < 0.0) {
+            return -1;
+        }
+        return answer;
+    }
+
+    /**
+     * Convert L* in L*a*b* to Y in XYZ.
+     *
+     * @param lstar L* in L*a*b*
+     * @return Y in XYZ
+     */
+    public static float lstarToY(float lstar) {
+        // http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html
+        float ke = 8.0f;
+        if (lstar > ke) {
+            return (float) (Math.pow(((lstar + 16.0) / 116.0), 3) * 100.0);
+        } else {
+            return (float) (lstar / (24389 / 27) * 100.0);
+        }
+    }
+
+    /**
+     * Convert Y in XYZ to L* in L*a*b*.
+     *
+     * @param y Y in XYZ
+     * @return L* in L*a*b*
+     */
+    public static float yToLstar(float y) {
+        y = y / 100.0f;
+        float e = 216.0f / 24389.0f;
+        float y_intermediate;
+        if (y <= e) {
+            y_intermediate = (24389.f / 27.f) * y;
+            // If y < e, can skip consecutive steps of / 116 + 16 followed by * 116 - 16.
+            return y_intermediate;
+        } else {
+            y_intermediate = (float) Math.cbrt(y);
+        }
+        return 116.f * y_intermediate - 16.f;
+    }
+
+
+    /**
+     * @return Contrast ratio between two Y values in XYZ space.
+     */
+    public static float contrastYs(float y1, float y2) {
+        final float lighter = Math.max(y1, y2);
+        final float darker = (lighter == y1) ? y2 : y1;
+        return (lighter + 5) / (darker + 5);
+    }
+}
diff --git a/core/java/com/android/internal/graphics/palette/LABCentroid.java b/core/java/com/android/internal/graphics/palette/LABCentroid.java
new file mode 100644
index 0000000..98d5d26
--- /dev/null
+++ b/core/java/com/android/internal/graphics/palette/LABCentroid.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.graphics.palette;
+
+import android.graphics.Color;
+import android.graphics.ColorSpace;
+
+/**
+ *  Allows quantizers to operate in the L*a*b* colorspace.
+ *  L*a*b* is a good choice for measuring distance between colors.
+ *  Better spaces, and better distance calculations even in L*a*b* exist, but measuring distance
+ *  in L*a*b* space, also known as deltaE, is a universally accepted standard across industries
+ *  and worldwide.
+ */
+public class LABCentroid implements CentroidProvider {
+    final ColorSpace.Connector mRgbToLab;
+    final ColorSpace.Connector mLabToRgb;
+
+    public LABCentroid() {
+        mRgbToLab = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.SRGB),
+                ColorSpace.get(ColorSpace.Named.CIE_LAB));
+        mLabToRgb = ColorSpace.connect(ColorSpace.get(ColorSpace.Named.CIE_LAB),
+                ColorSpace.get(ColorSpace.Named.SRGB));
+    }
+
+    @Override
+    public float[] getCentroid(int color) {
+        float r = Color.red(color) / 255.f;
+        float g =  Color.green(color) / 255.f;
+        float b = Color.blue(color) / 255.f;
+
+        float[] transform = mRgbToLab.transform(r, g, b);
+        return transform;
+    }
+
+    @Override
+    public int getColor(float[] centroid) {
+        float[] rgb = mLabToRgb.transform(centroid);
+        int color = Color.rgb(rgb[0], rgb[1], rgb[2]);
+        return color;
+    }
+
+    @Override
+    public float distance(float[] a, float[] b) {
+        // Standard v1 CIELAB deltaE formula, 1976 - easily improved upon, however,
+        // improvements do not significantly impact the Palette algorithm's results.
+        double dL = a[0] - b[0];
+        double dA = a[1] - b[1];
+        double dB = a[2] - b[2];
+        return (float) (Math.pow(dL, 2) + Math.pow(dA, 2) + Math.pow(dB, 2));
+    }
+}
diff --git a/core/java/com/android/internal/graphics/palette/Mean.java b/core/java/com/android/internal/graphics/palette/Mean.java
new file mode 100644
index 0000000..894f91b
--- /dev/null
+++ b/core/java/com/android/internal/graphics/palette/Mean.java
@@ -0,0 +1,45 @@
+/*
+ * 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.graphics.palette;
+
+import java.util.Random;
+
+/**
+ * Represents a centroid in Kmeans algorithms.
+ */
+public class Mean {
+    private static final Random RANDOM = new Random(0);
+
+    public float[] center;
+
+    /**
+     * Constructor.
+     *
+     * @param upperBound maximum value of a dimension in the space Kmeans is optimizing in
+     */
+    Mean(int upperBound) {
+        center =
+                new float[]{
+                        RANDOM.nextInt(upperBound + 1), RANDOM.nextInt(upperBound + 1),
+                        RANDOM.nextInt(upperBound + 1)
+                };
+    }
+
+    Mean(float[] center) {
+        this.center = center;
+    }
+}
diff --git a/core/java/com/android/internal/graphics/palette/MeanBucket.java b/core/java/com/android/internal/graphics/palette/MeanBucket.java
new file mode 100644
index 0000000..ae8858a
--- /dev/null
+++ b/core/java/com/android/internal/graphics/palette/MeanBucket.java
@@ -0,0 +1,42 @@
+/*
+ * 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.graphics.palette;
+
+import java.util.HashSet;
+import java.util.Set;
+
+class MeanBucket {
+    float[] mTotal = {0.f, 0.f, 0.f};
+    int mCount = 0;
+    Set<Integer> mColors = new HashSet<>();
+
+    void add(float[] colorAsDoubles, int color, int colorCount) {
+        assert (colorAsDoubles.length == 3);
+        mColors.add(color);
+        mTotal[0] += (colorAsDoubles[0] * colorCount);
+        mTotal[1] += (colorAsDoubles[1] * colorCount);
+        mTotal[2] += (colorAsDoubles[2] * colorCount);
+        mCount += colorCount;
+    }
+
+    float[] getCentroid() {
+        if (mCount == 0) {
+            return null;
+        }
+        return new float[]{mTotal[0] / mCount, mTotal[1] / mCount, mTotal[2] / mCount};
+    }
+}
diff --git a/core/java/com/android/internal/graphics/palette/Palette.java b/core/java/com/android/internal/graphics/palette/Palette.java
index a4f9a59..8b1137d 100644
--- a/core/java/com/android/internal/graphics/palette/Palette.java
+++ b/core/java/com/android/internal/graphics/palette/Palette.java
@@ -19,48 +19,24 @@
 import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.Px;
 import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.Rect;
-import android.os.AsyncTask;
-import android.util.ArrayMap;
 import android.util.Log;
-import android.util.SparseBooleanArray;
-import android.util.TimingLogger;
 
-import com.android.internal.graphics.ColorUtils;
-
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 
 
 /**
- * Copied from: /frameworks/support/v7/palette/src/main/java/android/support/v7/
- * graphics/Palette.java
- *
  * A helper class to extract prominent colors from an image.
- * <p>
- * A number of colors with different profiles are extracted from the image:
- * <ul>
- *     <li>Vibrant</li>
- *     <li>Vibrant Dark</li>
- *     <li>Vibrant Light</li>
- *     <li>Muted</li>
- *     <li>Muted Dark</li>
- *     <li>Muted Light</li>
- * </ul>
- * These can be retrieved from the appropriate getter method.
  *
- * <p>
- * Instances are created with a {@link Palette.Builder} which supports several options to tweak the
+ * <p>Instances are created with a {@link Builder} which supports several options to tweak the
  * generated Palette. See that class' documentation for more information.
- * <p>
- * Generation should always be completed on a background thread, ideally the one in
- * which you load your image on. {@link Palette.Builder} supports both synchronous and asynchronous
- * generation:
+ *
+ * <p>Generation should always be completed on a background thread, ideally the one in which you
+ * load your image on. {@link Builder} supports both synchronous and asynchronous generation:
  *
  * <pre>
  * // Synchronous
@@ -85,346 +61,59 @@
         /**
          * Called when the {@link Palette} has been generated.
          */
-        void onGenerated(Palette palette);
+        void onGenerated(@Nullable Palette palette);
     }
 
     static final int DEFAULT_RESIZE_BITMAP_AREA = 112 * 112;
     static final int DEFAULT_CALCULATE_NUMBER_COLORS = 16;
-
-    static final float MIN_CONTRAST_TITLE_TEXT = 3.0f;
-    static final float MIN_CONTRAST_BODY_TEXT = 4.5f;
-
     static final String LOG_TAG = "Palette";
-    static final boolean LOG_TIMINGS = false;
 
-    /**
-     * Start generating a {@link Palette} with the returned {@link Palette.Builder} instance.
-     */
-    public static Palette.Builder from(Bitmap bitmap) {
-        return new Palette.Builder(bitmap);
+    /** Start generating a {@link Palette} with the returned {@link Builder} instance. */
+    @NonNull
+    public static Builder from(@NonNull Bitmap bitmap, @NonNull Quantizer quantizer) {
+        return new Builder(bitmap, quantizer);
     }
 
     /**
      * Generate a {@link Palette} from the pre-generated list of {@link Palette.Swatch} swatches.
-     * This is useful for testing, or if you want to resurrect a {@link Palette} instance from a
-     * list of swatches. Will return null if the {@code swatches} is null.
+     * This
+     * is useful for testing, or if you want to resurrect a {@link Palette} instance from a list of
+     * swatches. Will return null if the {@code swatches} is null.
      */
-    public static Palette from(List<Palette.Swatch> swatches) {
-        return new Palette.Builder(swatches).generate();
+    @NonNull
+    public static Palette from(@NonNull List<Swatch> swatches) {
+        return new Builder(swatches).generate();
     }
 
-    /**
-     * @deprecated Use {@link Palette.Builder} to generate the Palette.
-     */
-    @Deprecated
-    public static Palette generate(Bitmap bitmap) {
-        return from(bitmap).generate();
-    }
+    private final List<Swatch> mSwatches;
 
-    /**
-     * @deprecated Use {@link Palette.Builder} to generate the Palette.
-     */
-    @Deprecated
-    public static Palette generate(Bitmap bitmap, int numColors) {
-        return from(bitmap).maximumColorCount(numColors).generate();
-    }
 
-    /**
-     * @deprecated Use {@link Palette.Builder} to generate the Palette.
-     */
-    @Deprecated
-    public static AsyncTask<Bitmap, Void, Palette> generateAsync(
-            Bitmap bitmap, Palette.PaletteAsyncListener listener) {
-        return from(bitmap).generate(listener);
-    }
+    @Nullable
+    private final Swatch mDominantSwatch;
 
-    /**
-     * @deprecated Use {@link Palette.Builder} to generate the Palette.
-     */
-    @Deprecated
-    public static AsyncTask<Bitmap, Void, Palette> generateAsync(
-            final Bitmap bitmap, final int numColors, final Palette.PaletteAsyncListener listener) {
-        return from(bitmap).maximumColorCount(numColors).generate(listener);
-    }
-
-    private final List<Palette.Swatch> mSwatches;
-    private final List<Target> mTargets;
-
-    private final Map<Target, Palette.Swatch> mSelectedSwatches;
-    private final SparseBooleanArray mUsedColors;
-
-    private final Palette.Swatch mDominantSwatch;
-
-    Palette(List<Palette.Swatch> swatches, List<Target> targets) {
+    Palette(List<Swatch> swatches) {
         mSwatches = swatches;
-        mTargets = targets;
-
-        mUsedColors = new SparseBooleanArray();
-        mSelectedSwatches = new ArrayMap<>();
-
         mDominantSwatch = findDominantSwatch();
     }
 
-    /**
-     * Returns all of the swatches which make up the palette.
-     */
+    /** Returns all of the swatches which make up the palette. */
     @NonNull
-    public List<Palette.Swatch> getSwatches() {
+    public List<Swatch> getSwatches() {
         return Collections.unmodifiableList(mSwatches);
     }
 
-    /**
-     * Returns the targets used to generate this palette.
-     */
-    @NonNull
-    public List<Target> getTargets() {
-        return Collections.unmodifiableList(mTargets);
-    }
-
-    /**
-     * Returns the most vibrant swatch in the palette. Might be null.
-     *
-     * @see Target#VIBRANT
-     */
+    /** Returns the swatch with the highest population, or null if there are no swatches. */
     @Nullable
-    public Palette.Swatch getVibrantSwatch() {
-        return getSwatchForTarget(Target.VIBRANT);
-    }
-
-    /**
-     * Returns a light and vibrant swatch from the palette. Might be null.
-     *
-     * @see Target#LIGHT_VIBRANT
-     */
-    @Nullable
-    public Palette.Swatch getLightVibrantSwatch() {
-        return getSwatchForTarget(Target.LIGHT_VIBRANT);
-    }
-
-    /**
-     * Returns a dark and vibrant swatch from the palette. Might be null.
-     *
-     * @see Target#DARK_VIBRANT
-     */
-    @Nullable
-    public Palette.Swatch getDarkVibrantSwatch() {
-        return getSwatchForTarget(Target.DARK_VIBRANT);
-    }
-
-    /**
-     * Returns a muted swatch from the palette. Might be null.
-     *
-     * @see Target#MUTED
-     */
-    @Nullable
-    public Palette.Swatch getMutedSwatch() {
-        return getSwatchForTarget(Target.MUTED);
-    }
-
-    /**
-     * Returns a muted and light swatch from the palette. Might be null.
-     *
-     * @see Target#LIGHT_MUTED
-     */
-    @Nullable
-    public Palette.Swatch getLightMutedSwatch() {
-        return getSwatchForTarget(Target.LIGHT_MUTED);
-    }
-
-    /**
-     * Returns a muted and dark swatch from the palette. Might be null.
-     *
-     * @see Target#DARK_MUTED
-     */
-    @Nullable
-    public Palette.Swatch getDarkMutedSwatch() {
-        return getSwatchForTarget(Target.DARK_MUTED);
-    }
-
-    /**
-     * Returns the most vibrant color in the palette as an RGB packed int.
-     *
-     * @param defaultColor value to return if the swatch isn't available
-     * @see #getVibrantSwatch()
-     */
-    @ColorInt
-    public int getVibrantColor(@ColorInt final int defaultColor) {
-        return getColorForTarget(Target.VIBRANT, defaultColor);
-    }
-
-    /**
-     * Returns a light and vibrant color from the palette as an RGB packed int.
-     *
-     * @param defaultColor value to return if the swatch isn't available
-     * @see #getLightVibrantSwatch()
-     */
-    @ColorInt
-    public int getLightVibrantColor(@ColorInt final int defaultColor) {
-        return getColorForTarget(Target.LIGHT_VIBRANT, defaultColor);
-    }
-
-    /**
-     * Returns a dark and vibrant color from the palette as an RGB packed int.
-     *
-     * @param defaultColor value to return if the swatch isn't available
-     * @see #getDarkVibrantSwatch()
-     */
-    @ColorInt
-    public int getDarkVibrantColor(@ColorInt final int defaultColor) {
-        return getColorForTarget(Target.DARK_VIBRANT, defaultColor);
-    }
-
-    /**
-     * Returns a muted color from the palette as an RGB packed int.
-     *
-     * @param defaultColor value to return if the swatch isn't available
-     * @see #getMutedSwatch()
-     */
-    @ColorInt
-    public int getMutedColor(@ColorInt final int defaultColor) {
-        return getColorForTarget(Target.MUTED, defaultColor);
-    }
-
-    /**
-     * Returns a muted and light color from the palette as an RGB packed int.
-     *
-     * @param defaultColor value to return if the swatch isn't available
-     * @see #getLightMutedSwatch()
-     */
-    @ColorInt
-    public int getLightMutedColor(@ColorInt final int defaultColor) {
-        return getColorForTarget(Target.LIGHT_MUTED, defaultColor);
-    }
-
-    /**
-     * Returns a muted and dark color from the palette as an RGB packed int.
-     *
-     * @param defaultColor value to return if the swatch isn't available
-     * @see #getDarkMutedSwatch()
-     */
-    @ColorInt
-    public int getDarkMutedColor(@ColorInt final int defaultColor) {
-        return getColorForTarget(Target.DARK_MUTED, defaultColor);
-    }
-
-    /**
-     * Returns the selected swatch for the given target from the palette, or {@code null} if one
-     * could not be found.
-     */
-    @Nullable
-    public Palette.Swatch getSwatchForTarget(@NonNull final Target target) {
-        return mSelectedSwatches.get(target);
-    }
-
-    /**
-     * Returns the selected color for the given target from the palette as an RGB packed int.
-     *
-     * @param defaultColor value to return if the swatch isn't available
-     */
-    @ColorInt
-    public int getColorForTarget(@NonNull final Target target, @ColorInt final int defaultColor) {
-        Palette.Swatch swatch = getSwatchForTarget(target);
-        return swatch != null ? swatch.getRgb() : defaultColor;
-    }
-
-    /**
-     * Returns the dominant swatch from the palette.
-     *
-     * <p>The dominant swatch is defined as the swatch with the greatest population (frequency)
-     * within the palette.</p>
-     */
-    @Nullable
-    public Palette.Swatch getDominantSwatch() {
+    public Swatch getDominantSwatch() {
         return mDominantSwatch;
     }
 
-    /**
-     * Returns the color of the dominant swatch from the palette, as an RGB packed int.
-     *
-     * @param defaultColor value to return if the swatch isn't available
-     * @see #getDominantSwatch()
-     */
-    @ColorInt
-    public int getDominantColor(@ColorInt int defaultColor) {
-        return mDominantSwatch != null ? mDominantSwatch.getRgb() : defaultColor;
-    }
-
-    void generate() {
-        // We need to make sure that the scored targets are generated first. This is so that
-        // inherited targets have something to inherit from
-        for (int i = 0, count = mTargets.size(); i < count; i++) {
-            final Target target = mTargets.get(i);
-            target.normalizeWeights();
-            mSelectedSwatches.put(target, generateScoredTarget(target));
-        }
-        // We now clear out the used colors
-        mUsedColors.clear();
-    }
-
-    private Palette.Swatch generateScoredTarget(final Target target) {
-        final Palette.Swatch maxScoreSwatch = getMaxScoredSwatchForTarget(target);
-        if (maxScoreSwatch != null && target.isExclusive()) {
-            // If we have a swatch, and the target is exclusive, add the color to the used list
-            mUsedColors.append(maxScoreSwatch.getRgb(), true);
-        }
-        return maxScoreSwatch;
-    }
-
-    private Palette.Swatch getMaxScoredSwatchForTarget(final Target target) {
-        float maxScore = 0;
-        Palette.Swatch maxScoreSwatch = null;
-        for (int i = 0, count = mSwatches.size(); i < count; i++) {
-            final Palette.Swatch swatch = mSwatches.get(i);
-            if (shouldBeScoredForTarget(swatch, target)) {
-                final float score = generateScore(swatch, target);
-                if (maxScoreSwatch == null || score > maxScore) {
-                    maxScoreSwatch = swatch;
-                    maxScore = score;
-                }
-            }
-        }
-        return maxScoreSwatch;
-    }
-
-    private boolean shouldBeScoredForTarget(final Palette.Swatch swatch, final Target target) {
-        // Check whether the HSL values are within the correct ranges, and this color hasn't
-        // been used yet.
-        final float hsl[] = swatch.getHsl();
-        return hsl[1] >= target.getMinimumSaturation() && hsl[1] <= target.getMaximumSaturation()
-                && hsl[2] >= target.getMinimumLightness() && hsl[2] <= target.getMaximumLightness()
-                && !mUsedColors.get(swatch.getRgb());
-    }
-
-    private float generateScore(Palette.Swatch swatch, Target target) {
-        final float[] hsl = swatch.getHsl();
-
-        float saturationScore = 0;
-        float luminanceScore = 0;
-        float populationScore = 0;
-
-        final int maxPopulation = mDominantSwatch != null ? mDominantSwatch.getPopulation() : 1;
-
-        if (target.getSaturationWeight() > 0) {
-            saturationScore = target.getSaturationWeight()
-                    * (1f - Math.abs(hsl[1] - target.getTargetSaturation()));
-        }
-        if (target.getLightnessWeight() > 0) {
-            luminanceScore = target.getLightnessWeight()
-                    * (1f - Math.abs(hsl[2] - target.getTargetLightness()));
-        }
-        if (target.getPopulationWeight() > 0) {
-            populationScore = target.getPopulationWeight()
-                    * (swatch.getPopulation() / (float) maxPopulation);
-        }
-
-        return saturationScore + luminanceScore + populationScore;
-    }
-
-    private Palette.Swatch findDominantSwatch() {
+    @Nullable
+    private Swatch findDominantSwatch() {
         int maxPop = Integer.MIN_VALUE;
-        Palette.Swatch maxSwatch = null;
+        Swatch maxSwatch = null;
         for (int i = 0, count = mSwatches.size(); i < count; i++) {
-            Palette.Swatch swatch = mSwatches.get(i);
+            Swatch swatch = mSwatches.get(i);
             if (swatch.getPopulation() > maxPop) {
                 maxSwatch = swatch;
                 maxPop = swatch.getPopulation();
@@ -433,148 +122,42 @@
         return maxSwatch;
     }
 
-    private static float[] copyHslValues(Palette.Swatch color) {
-        final float[] newHsl = new float[3];
-        System.arraycopy(color.getHsl(), 0, newHsl, 0, 3);
-        return newHsl;
-    }
-
     /**
      * Represents a color swatch generated from an image's palette. The RGB color can be retrieved
-     * by calling {@link #getRgb()}.
+     * by
+     * calling {@link #getInt()}.
      */
-    public static final class Swatch {
-        private final int mRed, mGreen, mBlue;
-        private final int mRgb;
+    public static class Swatch {
+        private final Color mColor;
         private final int mPopulation;
 
-        private boolean mGeneratedTextColors;
-        private int mTitleTextColor;
-        private int mBodyTextColor;
 
-        private float[] mHsl;
-
-        public Swatch(@ColorInt int color, int population) {
-            mRed = Color.red(color);
-            mGreen = Color.green(color);
-            mBlue = Color.blue(color);
-            mRgb = color;
+        public Swatch(@ColorInt int colorInt, int population) {
+            mColor = Color.valueOf(colorInt);
             mPopulation = population;
         }
 
-        Swatch(int red, int green, int blue, int population) {
-            mRed = red;
-            mGreen = green;
-            mBlue = blue;
-            mRgb = Color.rgb(red, green, blue);
-            mPopulation = population;
-        }
-
-        Swatch(float[] hsl, int population) {
-            this(ColorUtils.HSLToColor(hsl), population);
-            mHsl = hsl;
-        }
-
-        /**
-         * @return this swatch's RGB color value
-         */
+        /** @return this swatch's RGB color value */
         @ColorInt
-        public int getRgb() {
-            return mRgb;
+        public int getInt() {
+            return mColor.toArgb();
         }
 
-        /**
-         * Return this swatch's HSL values.
-         *     hsv[0] is Hue [0 .. 360)
-         *     hsv[1] is Saturation [0...1]
-         *     hsv[2] is Lightness [0...1]
-         */
-        public float[] getHsl() {
-            if (mHsl == null) {
-                mHsl = new float[3];
-            }
-            ColorUtils.RGBToHSL(mRed, mGreen, mBlue, mHsl);
-            return mHsl;
-        }
-
-        /**
-         * @return the number of pixels represented by this swatch
-         */
+        /** @return the number of pixels represented by this swatch */
         public int getPopulation() {
             return mPopulation;
         }
 
-        /**
-         * Returns an appropriate color to use for any 'title' text which is displayed over this
-         * {@link Palette.Swatch}'s color. This color is guaranteed to have sufficient contrast.
-         */
-        @ColorInt
-        public int getTitleTextColor() {
-            ensureTextColorsGenerated();
-            return mTitleTextColor;
-        }
-
-        /**
-         * Returns an appropriate color to use for any 'body' text which is displayed over this
-         * {@link Palette.Swatch}'s color. This color is guaranteed to have sufficient contrast.
-         */
-        @ColorInt
-        public int getBodyTextColor() {
-            ensureTextColorsGenerated();
-            return mBodyTextColor;
-        }
-
-        private void ensureTextColorsGenerated() {
-            if (!mGeneratedTextColors) {
-                // First check white, as most colors will be dark
-                final int lightBodyAlpha = ColorUtils.calculateMinimumAlpha(
-                        Color.WHITE, mRgb, MIN_CONTRAST_BODY_TEXT);
-                final int lightTitleAlpha = ColorUtils.calculateMinimumAlpha(
-                        Color.WHITE, mRgb, MIN_CONTRAST_TITLE_TEXT);
-
-                if (lightBodyAlpha != -1 && lightTitleAlpha != -1) {
-                    // If we found valid light values, use them and return
-                    mBodyTextColor = ColorUtils.setAlphaComponent(Color.WHITE, lightBodyAlpha);
-                    mTitleTextColor = ColorUtils.setAlphaComponent(Color.WHITE, lightTitleAlpha);
-                    mGeneratedTextColors = true;
-                    return;
-                }
-
-                final int darkBodyAlpha = ColorUtils.calculateMinimumAlpha(
-                        Color.BLACK, mRgb, MIN_CONTRAST_BODY_TEXT);
-                final int darkTitleAlpha = ColorUtils.calculateMinimumAlpha(
-                        Color.BLACK, mRgb, MIN_CONTRAST_TITLE_TEXT);
-
-                if (darkBodyAlpha != -1 && darkTitleAlpha != -1) {
-                    // If we found valid dark values, use them and return
-                    mBodyTextColor = ColorUtils.setAlphaComponent(Color.BLACK, darkBodyAlpha);
-                    mTitleTextColor = ColorUtils.setAlphaComponent(Color.BLACK, darkTitleAlpha);
-                    mGeneratedTextColors = true;
-                    return;
-                }
-
-                // If we reach here then we can not find title and body values which use the same
-                // lightness, we need to use mismatched values
-                mBodyTextColor = lightBodyAlpha != -1
-                        ? ColorUtils.setAlphaComponent(Color.WHITE, lightBodyAlpha)
-                        : ColorUtils.setAlphaComponent(Color.BLACK, darkBodyAlpha);
-                mTitleTextColor = lightTitleAlpha != -1
-                        ? ColorUtils.setAlphaComponent(Color.WHITE, lightTitleAlpha)
-                        : ColorUtils.setAlphaComponent(Color.BLACK, darkTitleAlpha);
-                mGeneratedTextColors = true;
-            }
-        }
-
         @Override
         public String toString() {
             return new StringBuilder(getClass().getSimpleName())
-                    .append(" [RGB: #").append(Integer.toHexString(getRgb())).append(']')
-                    .append(" [HSL: ").append(Arrays.toString(getHsl())).append(']')
-                    .append(" [Population: ").append(mPopulation).append(']')
-                    .append(" [Title Text: #").append(Integer.toHexString(getTitleTextColor()))
+                    .append(" [")
+                    .append(mColor)
                     .append(']')
-                    .append(" [Body Text: #").append(Integer.toHexString(getBodyTextColor()))
-                    .append(']').toString();
+                    .append(" [Population: ")
+                    .append(mPopulation)
+                    .append(']')
+                    .toString();
         }
 
         @Override
@@ -586,243 +169,168 @@
                 return false;
             }
 
-            Palette.Swatch
-                    swatch = (Palette.Swatch) o;
-            return mPopulation == swatch.mPopulation && mRgb == swatch.mRgb;
+            Swatch swatch = (Swatch) o;
+            return mPopulation == swatch.mPopulation && mColor.toArgb() == swatch.mColor.toArgb();
         }
 
         @Override
         public int hashCode() {
-            return 31 * mRgb + mPopulation;
+            return 31 * mColor.toArgb() + mPopulation;
         }
     }
 
-    /**
-     * Builder class for generating {@link Palette} instances.
-     */
-    public static final class Builder {
-        private final List<Palette.Swatch> mSwatches;
+    /** Builder class for generating {@link Palette} instances. */
+    public static class Builder {
+        @Nullable
+        private final List<Swatch> mSwatches;
+        @Nullable
         private final Bitmap mBitmap;
+        @Nullable
+        private Quantizer mQuantizer = new ColorCutQuantizer();
 
-        private final List<Target> mTargets = new ArrayList<>();
 
         private int mMaxColors = DEFAULT_CALCULATE_NUMBER_COLORS;
         private int mResizeArea = DEFAULT_RESIZE_BITMAP_AREA;
         private int mResizeMaxDimension = -1;
 
-        private final List<Palette.Filter> mFilters = new ArrayList<>();
+        @Nullable
         private Rect mRegion;
 
-        private Quantizer mQuantizer;
-
-        /**
-         * Construct a new {@link Palette.Builder} using a source {@link Bitmap}
-         */
-        public Builder(Bitmap bitmap) {
+        /** Construct a new {@link Builder} using a source {@link Bitmap} */
+        public Builder(@NonNull Bitmap bitmap, @NonNull Quantizer quantizer) {
             if (bitmap == null || bitmap.isRecycled()) {
                 throw new IllegalArgumentException("Bitmap is not valid");
             }
-            mFilters.add(DEFAULT_FILTER);
-            mBitmap = bitmap;
             mSwatches = null;
-
-            // Add the default targets
-            mTargets.add(Target.LIGHT_VIBRANT);
-            mTargets.add(Target.VIBRANT);
-            mTargets.add(Target.DARK_VIBRANT);
-            mTargets.add(Target.LIGHT_MUTED);
-            mTargets.add(Target.MUTED);
-            mTargets.add(Target.DARK_MUTED);
+            mBitmap = bitmap;
+            mQuantizer = quantizer == null ? new ColorCutQuantizer() : quantizer;
         }
 
         /**
-         * Construct a new {@link Palette.Builder} using a list of {@link Palette.Swatch} instances.
-         * Typically only used for testing.
+         * Construct a new {@link Builder} using a list of {@link Swatch} instances. Typically only
+         * used
+         * for testing.
          */
-        public Builder(List<Palette.Swatch> swatches) {
+        public Builder(@NonNull List<Swatch> swatches) {
             if (swatches == null || swatches.isEmpty()) {
                 throw new IllegalArgumentException("List of Swatches is not valid");
             }
-            mFilters.add(DEFAULT_FILTER);
             mSwatches = swatches;
             mBitmap = null;
+            mQuantizer = null;
         }
 
         /**
-         * Set the maximum number of colors to use in the quantization step when using a
-         * {@link android.graphics.Bitmap} as the source.
-         * <p>
-         * Good values for depend on the source image type. For landscapes, good values are in
-         * the range 10-16. For images which are largely made up of people's faces then this
-         * value should be increased to ~24.
+         * Set the maximum number of colors to use in the quantization step when using a {@link
+         * android.graphics.Bitmap} as the source.
+         *
+         * <p>Good values for depend on the source image type. For landscapes, good values are in
+         * the
+         * range 10-16. For images which are largely made up of people's faces then this value
+         * should be
+         * increased to ~24.
          */
         @NonNull
-        public Palette.Builder maximumColorCount(int colors) {
+        public Builder maximumColorCount(int colors) {
             mMaxColors = colors;
             return this;
         }
 
         /**
-         * Set the resize value when using a {@link android.graphics.Bitmap} as the source.
-         * If the bitmap's largest dimension is greater than the value specified, then the bitmap
-         * will be resized so that its largest dimension matches {@code maxDimension}. If the
-         * bitmap is smaller or equal, the original is used as-is.
-         *
-         * @deprecated Using {@link #resizeBitmapArea(int)} is preferred since it can handle
-         * abnormal aspect ratios more gracefully.
+         * Set the resize value when using a {@link android.graphics.Bitmap} as the source. If the
+         * bitmap's largest dimension is greater than the value specified, then the bitmap will be
+         * resized so that its largest dimension matches {@code maxDimension}. If the bitmap is
+         * smaller
+         * or equal, the original is used as-is.
          *
          * @param maxDimension the number of pixels that the max dimension should be scaled down to,
-         *                     or any value <= 0 to disable resizing.
+         *                     or
+         *                     any value <= 0 to disable resizing.
+         * @deprecated Using {@link #resizeBitmapArea(int)} is preferred since it can handle
+         * abnormal
+         * aspect ratios more gracefully.
          */
         @NonNull
         @Deprecated
-        public Palette.Builder resizeBitmapSize(final int maxDimension) {
+        public Builder resizeBitmapSize(int maxDimension) {
             mResizeMaxDimension = maxDimension;
             mResizeArea = -1;
             return this;
         }
 
         /**
-         * Set the resize value when using a {@link android.graphics.Bitmap} as the source.
-         * If the bitmap's area is greater than the value specified, then the bitmap
-         * will be resized so that its area matches {@code area}. If the
-         * bitmap is smaller or equal, the original is used as-is.
-         * <p>
-         * This value has a large effect on the processing time. The larger the resized image is,
-         * the greater time it will take to generate the palette. The smaller the image is, the
-         * more detail is lost in the resulting image and thus less precision for color selection.
+         * Set the resize value when using a {@link android.graphics.Bitmap} as the source. If the
+         * bitmap's area is greater than the value specified, then the bitmap will be resized so
+         * that
+         * its area matches {@code area}. If the bitmap is smaller or equal, the original is used
+         * as-is.
+         *
+         * <p>This value has a large effect on the processing time. The larger the resized image is,
+         * the
+         * greater time it will take to generate the palette. The smaller the image is, the more
+         * detail
+         * is lost in the resulting image and thus less precision for color selection.
          *
          * @param area the number of pixels that the intermediary scaled down Bitmap should cover,
-         *             or any value <= 0 to disable resizing.
+         *             or
+         *             any value <= 0 to disable resizing.
          */
         @NonNull
-        public Palette.Builder resizeBitmapArea(final int area) {
+        public Builder resizeBitmapArea(int area) {
             mResizeArea = area;
             mResizeMaxDimension = -1;
             return this;
         }
 
         /**
-         * Clear all added filters. This includes any default filters added automatically by
-         * {@link Palette}.
-         */
-        @NonNull
-        public Palette.Builder clearFilters() {
-            mFilters.clear();
-            return this;
-        }
-
-        /**
-         * Add a filter to be able to have fine grained control over which colors are
-         * allowed in the resulting palette.
-         *
-         * @param filter filter to add.
-         */
-        @NonNull
-        public Palette.Builder addFilter(
-                Palette.Filter filter) {
-            if (filter != null) {
-                mFilters.add(filter);
-            }
-            return this;
-        }
-
-        /**
-         * Set a specific quantization algorithm. {@link ColorCutQuantizer} will
-         * be used if unspecified.
-         *
-         * @param quantizer Quantizer implementation.
-         */
-        @NonNull
-        public Palette.Builder setQuantizer(Quantizer quantizer) {
-            mQuantizer = quantizer;
-            return this;
-        }
-
-        /**
          * Set a region of the bitmap to be used exclusively when calculating the palette.
-         * <p>This only works when the original input is a {@link Bitmap}.</p>
          *
-         * @param left The left side of the rectangle used for the region.
-         * @param top The top of the rectangle used for the region.
-         * @param right The right side of the rectangle used for the region.
+         * <p>This only works when the original input is a {@link Bitmap}.
+         *
+         * @param left   The left side of the rectangle used for the region.
+         * @param top    The top of the rectangle used for the region.
+         * @param right  The right side of the rectangle used for the region.
          * @param bottom The bottom of the rectangle used for the region.
          */
         @NonNull
-        public Palette.Builder setRegion(int left, int top, int right, int bottom) {
+        public Builder setRegion(@Px int left, @Px int top, @Px int right, @Px int bottom) {
             if (mBitmap != null) {
                 if (mRegion == null) mRegion = new Rect();
                 // Set the Rect to be initially the whole Bitmap
                 mRegion.set(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
                 // Now just get the intersection with the region
                 if (!mRegion.intersect(left, top, right, bottom)) {
-                    throw new IllegalArgumentException("The given region must intersect with "
-                            + "the Bitmap's dimensions.");
+                    throw new IllegalArgumentException(
+                            "The given region must intersect with " + "the Bitmap's dimensions.");
                 }
             }
             return this;
         }
 
-        /**
-         * Clear any previously region set via {@link #setRegion(int, int, int, int)}.
-         */
+        /** Clear any previously region set via {@link #setRegion(int, int, int, int)}. */
         @NonNull
-        public Palette.Builder clearRegion() {
+        public Builder clearRegion() {
             mRegion = null;
             return this;
         }
 
-        /**
-         * Add a target profile to be generated in the palette.
-         *
-         * <p>You can retrieve the result via {@link Palette#getSwatchForTarget(Target)}.</p>
-         */
-        @NonNull
-        public Palette.Builder addTarget(@NonNull final Target target) {
-            if (!mTargets.contains(target)) {
-                mTargets.add(target);
-            }
-            return this;
-        }
 
-        /**
-         * Clear all added targets. This includes any default targets added automatically by
-         * {@link Palette}.
-         */
-        @NonNull
-        public Palette.Builder clearTargets() {
-            if (mTargets != null) {
-                mTargets.clear();
-            }
-            return this;
-        }
-
-        /**
-         * Generate and return the {@link Palette} synchronously.
-         */
+        /** Generate and return the {@link Palette} synchronously. */
         @NonNull
         public Palette generate() {
-            final TimingLogger logger = LOG_TIMINGS
-                    ? new TimingLogger(LOG_TAG, "Generation")
-                    : null;
-
-            List<Palette.Swatch> swatches;
+            List<Swatch> swatches;
 
             if (mBitmap != null) {
                 // We have a Bitmap so we need to use quantization to reduce the number of colors
 
                 // First we'll scale down the bitmap if needed
-                final Bitmap bitmap = scaleBitmapDown(mBitmap);
+                Bitmap bitmap = scaleBitmapDown(mBitmap);
 
-                if (logger != null) {
-                    logger.addSplit("Processed Bitmap");
-                }
-
-                final Rect region = mRegion;
+                Rect region = mRegion;
                 if (bitmap != mBitmap && region != null) {
                     // If we have a scaled bitmap and a selected region, we need to scale down the
                     // region to match the new scale
-                    final double scale = bitmap.getWidth() / (double) mBitmap.getWidth();
+                    double scale = bitmap.getWidth() / (double) mBitmap.getWidth();
                     region.left = (int) Math.floor(region.left * scale);
                     region.top = (int) Math.floor(region.top * scale);
                     region.right = Math.min((int) Math.ceil(region.right * scale),
@@ -832,54 +340,47 @@
                 }
 
                 // Now generate a quantizer from the Bitmap
-                if (mQuantizer == null) {
-                    mQuantizer = new ColorCutQuantizer();
-                }
-                mQuantizer.quantize(getPixelsFromBitmap(bitmap),
-                            mMaxColors, mFilters.isEmpty() ? null :
-                            mFilters.toArray(new Palette.Filter[mFilters.size()]));
 
+                mQuantizer.quantize(
+                        getPixelsFromBitmap(bitmap),
+                        mMaxColors);
                 // If created a new bitmap, recycle it
                 if (bitmap != mBitmap) {
                     bitmap.recycle();
                 }
-
                 swatches = mQuantizer.getQuantizedColors();
-
-                if (logger != null) {
-                    logger.addSplit("Color quantization completed");
-                }
-            } else {
+            } else if (mSwatches != null) {
                 // Else we're using the provided swatches
                 swatches = mSwatches;
+            } else {
+                // The constructors enforce either a bitmap or swatches are present.
+                throw new AssertionError();
             }
 
             // Now create a Palette instance
-            final Palette p = new Palette(swatches, mTargets);
+            Palette p = new Palette(swatches);
             // And make it generate itself
-            p.generate();
-
-            if (logger != null) {
-                logger.addSplit("Created Palette");
-                logger.dumpToLog();
-            }
 
             return p;
         }
 
         /**
-         * Generate the {@link Palette} asynchronously. The provided listener's
-         * {@link Palette.PaletteAsyncListener#onGenerated} method will be called with the palette when
-         * generated.
+         * Generate the {@link Palette} asynchronously. The provided listener's {@link
+         * PaletteAsyncListener#onGenerated} method will be called with the palette when generated.
+         *
+         * @deprecated Use the standard <code>java.util.concurrent</code> or <a
+         * href="https://developer.android.com/topic/libraries/architecture/coroutines">Kotlin
+         * concurrency utilities</a> to call {@link #generate()} instead.
          */
         @NonNull
-        public AsyncTask<Bitmap, Void, Palette> generate(final Palette.PaletteAsyncListener listener) {
-            if (listener == null) {
-                throw new IllegalArgumentException("listener can not be null");
-            }
+        @Deprecated
+        public android.os.AsyncTask<Bitmap, Void, Palette> generate(
+                @NonNull PaletteAsyncListener listener) {
+            assert (listener != null);
 
-            return new AsyncTask<Bitmap, Void, Palette>() {
+            return new android.os.AsyncTask<Bitmap, Void, Palette>() {
                 @Override
+                @Nullable
                 protected Palette doInBackground(Bitmap... params) {
                     try {
                         return generate();
@@ -890,16 +391,16 @@
                 }
 
                 @Override
-                protected void onPostExecute(Palette colorExtractor) {
+                protected void onPostExecute(@Nullable Palette colorExtractor) {
                     listener.onGenerated(colorExtractor);
                 }
-            }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mBitmap);
+            }.executeOnExecutor(android.os.AsyncTask.THREAD_POOL_EXECUTOR, mBitmap);
         }
 
         private int[] getPixelsFromBitmap(Bitmap bitmap) {
-            final int bitmapWidth = bitmap.getWidth();
-            final int bitmapHeight = bitmap.getHeight();
-            final int[] pixels = new int[bitmapWidth * bitmapHeight];
+            int bitmapWidth = bitmap.getWidth();
+            int bitmapHeight = bitmap.getHeight();
+            int[] pixels = new int[bitmapWidth * bitmapHeight];
             bitmap.getPixels(pixels, 0, bitmapWidth, 0, 0, bitmapWidth, bitmapHeight);
 
             if (mRegion == null) {
@@ -908,32 +409,34 @@
             } else {
                 // If we do have a region, lets create a subset array containing only the region's
                 // pixels
-                final int regionWidth = mRegion.width();
-                final int regionHeight = mRegion.height();
+                int regionWidth = mRegion.width();
+                int regionHeight = mRegion.height();
                 // pixels contains all of the pixels, so we need to iterate through each row and
                 // copy the regions pixels into a new smaller array
-                final int[] subsetPixels = new int[regionWidth * regionHeight];
+                int[] subsetPixels = new int[regionWidth * regionHeight];
                 for (int row = 0; row < regionHeight; row++) {
-                    System.arraycopy(pixels, ((row + mRegion.top) * bitmapWidth) + mRegion.left,
-                            subsetPixels, row * regionWidth, regionWidth);
+                    System.arraycopy(
+                            pixels,
+                            ((row + mRegion.top) * bitmapWidth) + mRegion.left,
+                            subsetPixels,
+                            row * regionWidth,
+                            regionWidth);
                 }
                 return subsetPixels;
             }
         }
 
-        /**
-         * Scale the bitmap down as needed.
-         */
-        private Bitmap scaleBitmapDown(final Bitmap bitmap) {
+        /** Scale the bitmap down as needed. */
+        private Bitmap scaleBitmapDown(Bitmap bitmap) {
             double scaleRatio = -1;
 
             if (mResizeArea > 0) {
-                final int bitmapArea = bitmap.getWidth() * bitmap.getHeight();
+                int bitmapArea = bitmap.getWidth() * bitmap.getHeight();
                 if (bitmapArea > mResizeArea) {
                     scaleRatio = Math.sqrt(mResizeArea / (double) bitmapArea);
                 }
             } else if (mResizeMaxDimension > 0) {
-                final int maxDimension = Math.max(bitmap.getWidth(), bitmap.getHeight());
+                int maxDimension = Math.max(bitmap.getWidth(), bitmap.getHeight());
                 if (maxDimension > mResizeMaxDimension) {
                     scaleRatio = mResizeMaxDimension / (double) maxDimension;
                 }
@@ -944,11 +447,13 @@
                 return bitmap;
             }
 
-            return Bitmap.createScaledBitmap(bitmap,
+            return Bitmap.createScaledBitmap(
+                    bitmap,
                     (int) Math.ceil(bitmap.getWidth() * scaleRatio),
                     (int) Math.ceil(bitmap.getHeight() * scaleRatio),
                     false);
         }
+
     }
 
     /**
@@ -961,9 +466,7 @@
          *
          * @param rgb the color in RGB888.
          * @param hsl HSL representation of the color.
-         *
          * @return true if the color is allowed, false if not.
-         *
          * @see Palette.Builder#addFilter(Palette.Filter)
          */
         boolean isAllowed(int rgb, float[] hsl);
@@ -1004,3 +507,4 @@
         }
     };
 }
+
diff --git a/core/java/com/android/internal/graphics/palette/Quantizer.java b/core/java/com/android/internal/graphics/palette/Quantizer.java
index db60f2e..a219ea3 100644
--- a/core/java/com/android/internal/graphics/palette/Quantizer.java
+++ b/core/java/com/android/internal/graphics/palette/Quantizer.java
@@ -22,6 +22,15 @@
  * Definition of an algorithm that receives pixels and outputs a list of colors.
  */
 public interface Quantizer {
-    void quantize(final int[] pixels, final int maxColors, final Palette.Filter[] filters);
+    /**
+     * Create colors representative of the colors present in pixels.
+     * @param pixels Set of ARGB representation of a color.
+     * @param maxColors number of colors to generate
+     */
+    void quantize(int[] pixels, int maxColors);
+
+    /**
+     * List of colors generated by previous call to quantize.
+     */
     List<Palette.Swatch> getQuantizedColors();
 }
diff --git a/core/java/com/android/internal/graphics/palette/Target.java b/core/java/com/android/internal/graphics/palette/Target.java
index 0540d80..96e7faa 100644
--- a/core/java/com/android/internal/graphics/palette/Target.java
+++ b/core/java/com/android/internal/graphics/palette/Target.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 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.
@@ -16,368 +16,234 @@
 
 package com.android.internal.graphics.palette;
 
-/*
- * Copyright 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
 
 import android.annotation.FloatRange;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
 
 /**
- * Copied from: frameworks/support/v7/palette/src/main/java/android/support/v7/graphics/Target.java
- *
- * A class which allows custom selection of colors in a {@link Palette}'s generation. Instances
- * can be created via the {@link android.support.v7.graphics.Target.Builder} class.
- *
- * <p>To use the target, use the {@link Palette.Builder#addTarget(Target)} API when building a
- * Palette.</p>
+ * A class which allows custom selection of colors in a {@link Palette}'s generation. Instances can
+ * be created via the {@link Builder} class.
  */
+
 public final class Target {
+    private static final float WEIGHT_CHROMA = 0.5f;
+    private static final float WEIGHT_RELATIVE_LUMINANCE = 0.5f;
+    private static final float WEIGHT_POPULATION = 0.3f;
+    private static final float WEIGHT_HUE = 0.2f;
 
-    private static final float TARGET_DARK_LUMA = 0.26f;
-    private static final float MAX_DARK_LUMA = 0.45f;
+    // Arbitrarily chosen, except max - CAM16 chroma has a ceiling of 130, based on unit testing.
+    private static final float DEFAULT_CHROMA_MIN = 0.f;
+    private static final float DEFAULT_CHROMA_MAX = 130.f;
+    private static final float DEFAULT_CHROMA_TARGET = 30.f;
 
-    private static final float MIN_LIGHT_LUMA = 0.55f;
-    private static final float TARGET_LIGHT_LUMA = 0.74f;
-
-    private static final float MIN_NORMAL_LUMA = 0.3f;
-    private static final float TARGET_NORMAL_LUMA = 0.5f;
-    private static final float MAX_NORMAL_LUMA = 0.7f;
-
-    private static final float TARGET_MUTED_SATURATION = 0.3f;
-    private static final float MAX_MUTED_SATURATION = 0.4f;
-
-    private static final float TARGET_VIBRANT_SATURATION = 1f;
-    private static final float MIN_VIBRANT_SATURATION = 0.35f;
-
-    private static final float WEIGHT_SATURATION = 0.24f;
-    private static final float WEIGHT_LUMA = 0.52f;
-    private static final float WEIGHT_POPULATION = 0.24f;
-
-    static final int INDEX_MIN = 0;
-    static final int INDEX_TARGET = 1;
-    static final int INDEX_MAX = 2;
-
-    static final int INDEX_WEIGHT_SAT = 0;
-    static final int INDEX_WEIGHT_LUMA = 1;
-    static final int INDEX_WEIGHT_POP = 2;
-
-    /**
-     * A target which has the characteristics of a vibrant color which is light in luminance.
-     */
-    public static final Target LIGHT_VIBRANT;
-
-    /**
-     * A target which has the characteristics of a vibrant color which is neither light or dark.
-     */
-    public static final Target VIBRANT;
-
-    /**
-     * A target which has the characteristics of a vibrant color which is dark in luminance.
-     */
-    public static final Target DARK_VIBRANT;
-
-    /**
-     * A target which has the characteristics of a muted color which is light in luminance.
-     */
-    public static final Target LIGHT_MUTED;
-
-    /**
-     * A target which has the characteristics of a muted color which is neither light or dark.
-     */
-    public static final Target MUTED;
-
-    /**
-     * A target which has the characteristics of a muted color which is dark in luminance.
-     */
-    public static final Target DARK_MUTED;
-
-    static {
-        LIGHT_VIBRANT = new Target();
-        setDefaultLightLightnessValues(LIGHT_VIBRANT);
-        setDefaultVibrantSaturationValues(LIGHT_VIBRANT);
-
-        VIBRANT = new Target();
-        setDefaultNormalLightnessValues(VIBRANT);
-        setDefaultVibrantSaturationValues(VIBRANT);
-
-        DARK_VIBRANT = new Target();
-        setDefaultDarkLightnessValues(DARK_VIBRANT);
-        setDefaultVibrantSaturationValues(DARK_VIBRANT);
-
-        LIGHT_MUTED = new Target();
-        setDefaultLightLightnessValues(LIGHT_MUTED);
-        setDefaultMutedSaturationValues(LIGHT_MUTED);
-
-        MUTED = new Target();
-        setDefaultNormalLightnessValues(MUTED);
-        setDefaultMutedSaturationValues(MUTED);
-
-        DARK_MUTED = new Target();
-        setDefaultDarkLightnessValues(DARK_MUTED);
-        setDefaultMutedSaturationValues(DARK_MUTED);
-    }
-
-    final float[] mSaturationTargets = new float[3];
-    final float[] mLightnessTargets = new float[3];
-    final float[] mWeights = new float[3];
-    boolean mIsExclusive = true; // default to true
+    private float mTargetRelativeLuminance = -1.0f;
+    private float mChromaWeight;
+    private float mChromaTarget;
+    private float mChromaMin;
+    private float mChromaMax;
+    private float mRelativeLuminanceWeight;
+    private float mPopulationWeight;
+    private float mHueWeight;
+    private float mTargetHue;
 
     Target() {
-        setTargetDefaultValues(mSaturationTargets);
-        setTargetDefaultValues(mLightnessTargets);
-        setDefaultWeights();
+        mChromaMax = DEFAULT_CHROMA_MAX;
+        mChromaMin = DEFAULT_CHROMA_MIN;
+        mChromaTarget = DEFAULT_CHROMA_TARGET;
+        mChromaWeight =   WEIGHT_CHROMA;
+        mRelativeLuminanceWeight = WEIGHT_RELATIVE_LUMINANCE;
+        mPopulationWeight = WEIGHT_POPULATION;
+        mHueWeight = WEIGHT_HUE;
     }
 
-    Target(Target from) {
-        System.arraycopy(from.mSaturationTargets, 0, mSaturationTargets, 0,
-                mSaturationTargets.length);
-        System.arraycopy(from.mLightnessTargets, 0, mLightnessTargets, 0,
-                mLightnessTargets.length);
-        System.arraycopy(from.mWeights, 0, mWeights, 0, mWeights.length);
+    Target(@NonNull Target from) {
+        mTargetRelativeLuminance = from.mTargetRelativeLuminance;
+        mChromaWeight = from.mChromaWeight;
+        mRelativeLuminanceWeight = from.mRelativeLuminanceWeight;
+        mPopulationWeight = from.mPopulationWeight;
+        mHueWeight = from.mHueWeight;
+        mChromaTarget = from.mChromaTarget;
+        mChromaMin = from.mChromaMin;
+        mChromaMax = from.mChromaMax;
+    }
+
+    /** The relative luminance value for this target. */
+    @FloatRange(from = 0, to = 100)
+    public float getTargetRelativeLuminance() {
+        return mTargetRelativeLuminance;
+    }
+
+    /** The relative luminance value for this target. */
+    @FloatRange(from = 0, to = 100)
+    public float getTargetPerceptualLuminance() {
+        return Contrast.yToLstar(mTargetRelativeLuminance);
+    }
+
+    /** The minimum chroma value for this target. */
+    @FloatRange(from = 0, to = 100)
+    public float getMinimumChroma() {
+        return mChromaMin;
+    }
+
+    /** The target chroma value for this target. */
+    @FloatRange(from = 0, to = 100)
+    public float getTargetChroma() {
+        return mChromaTarget;
+    }
+
+    /** The maximum chroma value for this target. */
+    @FloatRange(from = 0, to = 130)
+    public float getMaximumChroma() {
+        return mChromaMax;
+    }
+
+    /** The target hue value for this target. */
+    @FloatRange(from = 0, to = 100)
+    public float getTargetHue() {
+        return mTargetHue;
     }
 
     /**
-     * The minimum saturation value for this target.
-     */
-    @FloatRange(from = 0, to = 1)
-    public float getMinimumSaturation() {
-        return mSaturationTargets[INDEX_MIN];
-    }
-
-    /**
-     * The target saturation value for this target.
-     */
-    @FloatRange(from = 0, to = 1)
-    public float getTargetSaturation() {
-        return mSaturationTargets[INDEX_TARGET];
-    }
-
-    /**
-     * The maximum saturation value for this target.
-     */
-    @FloatRange(from = 0, to = 1)
-    public float getMaximumSaturation() {
-        return mSaturationTargets[INDEX_MAX];
-    }
-
-    /**
-     * The minimum lightness value for this target.
-     */
-    @FloatRange(from = 0, to = 1)
-    public float getMinimumLightness() {
-        return mLightnessTargets[INDEX_MIN];
-    }
-
-    /**
-     * The target lightness value for this target.
-     */
-    @FloatRange(from = 0, to = 1)
-    public float getTargetLightness() {
-        return mLightnessTargets[INDEX_TARGET];
-    }
-
-    /**
-     * The maximum lightness value for this target.
-     */
-    @FloatRange(from = 0, to = 1)
-    public float getMaximumLightness() {
-        return mLightnessTargets[INDEX_MAX];
-    }
-
-    /**
-     * Returns the weight of importance that this target places on a color's saturation within
-     * the image.
+     * Returns the weight of importance that this target places on a color's chroma within the
+     * image.
      *
      * <p>The larger the weight, relative to the other weights, the more important that a color
-     * being close to the target value has on selection.</p>
+     * being
+     * close to the target value has on selection.
      *
-     * @see #getTargetSaturation()
+     * @see #getTargetChroma()
      */
-    public float getSaturationWeight() {
-        return mWeights[INDEX_WEIGHT_SAT];
+    public float getChromaWeight() {
+        return mChromaWeight;
     }
 
     /**
-     * Returns the weight of importance that this target places on a color's lightness within
-     * the image.
+     * Returns the weight of importance that this target places on a color's lightness within the
+     * image.
      *
      * <p>The larger the weight, relative to the other weights, the more important that a color
-     * being close to the target value has on selection.</p>
+     * being
+     * close to the target value has on selection.
      *
-     * @see #getTargetLightness()
+     * @see #getTargetRelativeLuminance()
      */
     public float getLightnessWeight() {
-        return mWeights[INDEX_WEIGHT_LUMA];
+        return mRelativeLuminanceWeight;
     }
 
     /**
-     * Returns the weight of importance that this target places on a color's population within
-     * the image.
+     * Returns the weight of importance that this target places on a color's population within the
+     * image.
      *
-     * <p>The larger the weight, relative to the other weights, the more important that a
-     * color's population being close to the most populous has on selection.</p>
+     * <p>The larger the weight, relative to the other weights, the more important that a color's
+     * population being close to the most populous has on selection.
      */
     public float getPopulationWeight() {
-        return mWeights[INDEX_WEIGHT_POP];
+        return mPopulationWeight;
     }
 
     /**
-     * Returns whether any color selected for this target is exclusive for this target only.
+     * Returns the weight of importance that this target places on a color's hue.
      *
-     * <p>If false, then the color can be selected for other targets.</p>
+     * <p>The larger the weight, relative to the other weights, the more important that a color's
+     * hue being close to the desired hue has on selection.
      */
-    public boolean isExclusive() {
-        return mIsExclusive;
+    public float getHueWeight() {
+        return mHueWeight;
     }
 
-    private static void setTargetDefaultValues(final float[] values) {
-        values[INDEX_MIN] = 0f;
-        values[INDEX_TARGET] = 0.5f;
-        values[INDEX_MAX] = 1f;
-    }
 
-    private void setDefaultWeights() {
-        mWeights[INDEX_WEIGHT_SAT] = WEIGHT_SATURATION;
-        mWeights[INDEX_WEIGHT_LUMA] = WEIGHT_LUMA;
-        mWeights[INDEX_WEIGHT_POP] = WEIGHT_POPULATION;
-    }
-
-    void normalizeWeights() {
-        float sum = 0;
-        for (int i = 0, z = mWeights.length; i < z; i++) {
-            float weight = mWeights[i];
-            if (weight > 0) {
-                sum += weight;
-            }
-        }
-        if (sum != 0) {
-            for (int i = 0, z = mWeights.length; i < z; i++) {
-                if (mWeights[i] > 0) {
-                    mWeights[i] /= sum;
-                }
-            }
-        }
-    }
-
-    private static void setDefaultDarkLightnessValues(Target target) {
-        target.mLightnessTargets[INDEX_TARGET] = TARGET_DARK_LUMA;
-        target.mLightnessTargets[INDEX_MAX] = MAX_DARK_LUMA;
-    }
-
-    private static void setDefaultNormalLightnessValues(Target target) {
-        target.mLightnessTargets[INDEX_MIN] = MIN_NORMAL_LUMA;
-        target.mLightnessTargets[INDEX_TARGET] = TARGET_NORMAL_LUMA;
-        target.mLightnessTargets[INDEX_MAX] = MAX_NORMAL_LUMA;
-    }
-
-    private static void setDefaultLightLightnessValues(Target target) {
-        target.mLightnessTargets[INDEX_MIN] = MIN_LIGHT_LUMA;
-        target.mLightnessTargets[INDEX_TARGET] = TARGET_LIGHT_LUMA;
-    }
-
-    private static void setDefaultVibrantSaturationValues(Target target) {
-        target.mSaturationTargets[INDEX_MIN] = MIN_VIBRANT_SATURATION;
-        target.mSaturationTargets[INDEX_TARGET] = TARGET_VIBRANT_SATURATION;
-    }
-
-    private static void setDefaultMutedSaturationValues(Target target) {
-        target.mSaturationTargets[INDEX_TARGET] = TARGET_MUTED_SATURATION;
-        target.mSaturationTargets[INDEX_MAX] = MAX_MUTED_SATURATION;
-    }
-
-    /**
-     * Builder class for generating custom {@link Target} instances.
-     */
-    public final static class Builder {
+    /** Builder class for generating custom {@link Target} instances. */
+    public static class Builder {
         private final Target mTarget;
 
-        /**
-         * Create a new {@link Target} builder from scratch.
-         */
+        /** Create a new {@link Target} builder from scratch. */
         public Builder() {
             mTarget = new Target();
         }
 
-        /**
-         * Create a new builder based on an existing {@link Target}.
-         */
-        public Builder(Target target) {
+        /** Create a new builder based on an existing {@link Target}. */
+        public Builder(@NonNull Target target) {
             mTarget = new Target(target);
         }
 
-        /**
-         * Set the minimum saturation value for this target.
-         */
-        public Target.Builder setMinimumSaturation(@FloatRange(from = 0, to = 1) float value) {
-            mTarget.mSaturationTargets[INDEX_MIN] = value;
+        /** Set the minimum chroma value for this target. */
+        @NonNull
+        public Builder setMinimumChroma(@FloatRange(from = 0, to = 100) float value) {
+            mTarget.mChromaMin = value;
+            return this;
+        }
+
+        /** Set the target/ideal chroma value for this target. */
+        @NonNull
+        public Builder setTargetChroma(@FloatRange(from = 0, to = 100) float value) {
+            mTarget.mChromaTarget = value;
+            return this;
+        }
+
+        /** Set the maximum chroma value for this target. */
+        @NonNull
+        public Builder setMaximumChroma(@FloatRange(from = 0, to = 100) float value) {
+            mTarget.mChromaMax = value;
+            return this;
+        }
+
+        /** Set the minimum lightness value for this target, using Y in XYZ color space. */
+        @NonNull
+        public Builder setTargetRelativeLuminance(@FloatRange(from = 0, to = 100) float value) {
+            mTarget.mTargetRelativeLuminance = value;
+            return this;
+        }
+
+        /** Set the minimum lightness value for this target, using L* in LAB color space. */
+        @NonNull
+        public Builder setTargetPerceptualLuminance(@FloatRange(from = 0, to = 100) float value) {
+            mTarget.mTargetRelativeLuminance = Contrast.lstarToY(value);
             return this;
         }
 
         /**
-         * Set the target/ideal saturation value for this target.
+         * Set the hue desired from the target. This hue is not enforced, the only consequence
+         * is points will be awarded to seed colors the closer they are to this hue.
          */
-        public Target.Builder setTargetSaturation(@FloatRange(from = 0, to = 1) float value) {
-            mTarget.mSaturationTargets[INDEX_TARGET] = value;
+        @NonNull
+        public Builder setTargetHue(@IntRange(from = 0, to = 360) int hue) {
+            mTarget.mTargetHue = hue;
+            return this;
+        }
+
+        /** Sets lightness value for this target. */
+        @NonNull
+        public Builder setContrastRatio(
+                @FloatRange(from = 1, to = 21) float value,
+                @FloatRange(from = 0, to = 100) float relativeLuminance) {
+            float counterpartY = relativeLuminance;
+            float lstar = Contrast.yToLstar(counterpartY);
+
+            float targetY;
+            if (lstar < 50) {
+                targetY = Contrast.lighterY(counterpartY, value);
+            } else {
+                targetY = Contrast.darkerY(counterpartY, value);
+            }
+            mTarget.mTargetRelativeLuminance = targetY;
             return this;
         }
 
         /**
-         * Set the maximum saturation value for this target.
-         */
-        public Target.Builder setMaximumSaturation(@FloatRange(from = 0, to = 1) float value) {
-            mTarget.mSaturationTargets[INDEX_MAX] = value;
-            return this;
-        }
-
-        /**
-         * Set the minimum lightness value for this target.
-         */
-        public Target.Builder setMinimumLightness(@FloatRange(from = 0, to = 1) float value) {
-            mTarget.mLightnessTargets[INDEX_MIN] = value;
-            return this;
-        }
-
-        /**
-         * Set the target/ideal lightness value for this target.
-         */
-        public Target.Builder setTargetLightness(@FloatRange(from = 0, to = 1) float value) {
-            mTarget.mLightnessTargets[INDEX_TARGET] = value;
-            return this;
-        }
-
-        /**
-         * Set the maximum lightness value for this target.
-         */
-        public Target.Builder setMaximumLightness(@FloatRange(from = 0, to = 1) float value) {
-            mTarget.mLightnessTargets[INDEX_MAX] = value;
-            return this;
-        }
-
-        /**
-         * Set the weight of importance that this target will place on saturation values.
+         * Set the weight of importance that this target will place on chroma values.
          *
          * <p>The larger the weight, relative to the other weights, the more important that a color
-         * being close to the target value has on selection.</p>
+         * being close to the target value has on selection.
          *
-         * <p>A weight of 0 means that it has no weight, and thus has no
-         * bearing on the selection.</p>
+         * <p>A weight of 0 means that it has no weight, and thus has no bearing on the selection.
          *
-         * @see #setTargetSaturation(float)
+         * @see #setTargetChroma(float)
          */
-        public Target.Builder setSaturationWeight(@FloatRange(from = 0) float weight) {
-            mTarget.mWeights[INDEX_WEIGHT_SAT] = weight;
+        @NonNull
+        public Builder setChromaWeight(@FloatRange(from = 0) float weight) {
+            mTarget.mChromaWeight = weight;
             return this;
         }
 
@@ -385,51 +251,40 @@
          * Set the weight of importance that this target will place on lightness values.
          *
          * <p>The larger the weight, relative to the other weights, the more important that a color
-         * being close to the target value has on selection.</p>
+         * being close to the target value has on selection.
          *
-         * <p>A weight of 0 means that it has no weight, and thus has no
-         * bearing on the selection.</p>
+         * <p>A weight of 0 means that it has no weight, and thus has no bearing on the selection.
          *
-         * @see #setTargetLightness(float)
+         * @see #setTargetRelativeLuminance(float)
          */
-        public Target.Builder setLightnessWeight(@FloatRange(from = 0) float weight) {
-            mTarget.mWeights[INDEX_WEIGHT_LUMA] = weight;
+        @NonNull
+        public Builder setLightnessWeight(@FloatRange(from = 0) float weight) {
+            mTarget.mRelativeLuminanceWeight = weight;
             return this;
         }
 
         /**
          * Set the weight of importance that this target will place on a color's population within
-         * the image.
+         * the
+         * image.
          *
          * <p>The larger the weight, relative to the other weights, the more important that a
-         * color's population being close to the most populous has on selection.</p>
+         * color's
+         * population being close to the most populous has on selection.
          *
-         * <p>A weight of 0 means that it has no weight, and thus has no
-         * bearing on the selection.</p>
+         * <p>A weight of 0 means that it has no weight, and thus has no bearing on the selection.
          */
-        public Target.Builder setPopulationWeight(@FloatRange(from = 0) float weight) {
-            mTarget.mWeights[INDEX_WEIGHT_POP] = weight;
+        @NonNull
+        public Builder setPopulationWeight(@FloatRange(from = 0) float weight) {
+            mTarget.mPopulationWeight = weight;
             return this;
         }
 
-        /**
-         * Set whether any color selected for this target is exclusive to this target only.
-         * Defaults to true.
-         *
-         * @param exclusive true if any the color is exclusive to this target, or false is the
-         *                  color can be selected for other targets.
-         */
-        public Target.Builder setExclusive(boolean exclusive) {
-            mTarget.mIsExclusive = exclusive;
-            return this;
-        }
 
-        /**
-         * Builds and returns the resulting {@link Target}.
-         */
+        /** Builds and returns the resulting {@link Target}. */
+        @NonNull
         public Target build() {
             return mTarget;
         }
     }
-
-}
\ No newline at end of file
+}
diff --git a/core/java/com/android/internal/graphics/palette/VariationalKMeansQuantizer.java b/core/java/com/android/internal/graphics/palette/VariationalKMeansQuantizer.java
index b035535..d791f7b 100644
--- a/core/java/com/android/internal/graphics/palette/VariationalKMeansQuantizer.java
+++ b/core/java/com/android/internal/graphics/palette/VariationalKMeansQuantizer.java
@@ -70,10 +70,9 @@
      *
      * @param pixels Pixels to quantize.
      * @param maxColors Maximum number of clusters to extract.
-     * @param filters Colors that should be ignored
      */
     @Override
-    public void quantize(int[] pixels, int maxColors, Palette.Filter[] filters) {
+    public void quantize(int[] pixels, int maxColors) {
         // Start by converting all colors to HSL.
         // HLS is way more meaningful for clustering than RGB.
         final float[] hsl = {0, 0, 0};
@@ -111,16 +110,18 @@
 
         // Convert data to final format, de-normalizing the hue.
         mQuantizedColors = new ArrayList<>();
+        float[] mHsl = new float[3];
         for (KMeans.Mean mean : optimalMeans) {
             if (mean.getItems().size() == 0) {
                 continue;
             }
             float[] centroid = mean.getCentroid();
-            mQuantizedColors.add(new Palette.Swatch(new float[]{
-                    centroid[0] * 360f,
-                    centroid[1],
-                    centroid[2]
-            }, mean.getItems().size()));
+
+            mHsl[0] = centroid[0] * 360f;
+            mHsl[1] = centroid[1];
+            mHsl[2] = centroid[2];
+            int color = ColorUtils.HSLToColor(mHsl);
+            mQuantizedColors.add(new Palette.Swatch(color, mean.getItems().size()));
         }
     }
 
diff --git a/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java b/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java
new file mode 100644
index 0000000..a87a34f
--- /dev/null
+++ b/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java
@@ -0,0 +1,269 @@
+/*
+ * 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.graphics.palette;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ * A color quantizer based on the Kmeans algorithm.
+ *
+ * This is an implementation of Kmeans based on Celebi's 2011 paper,
+ * "Improving the Performance of K-Means for Color Quantization". In the paper, this algorithm is
+ * referred to as "WSMeans", or, "Weighted Square Means" The main advantages of this Kmeans
+ * implementation are taking advantage of triangle properties to avoid distance calculations, as
+ * well as indexing colors by their count, thus minimizing the number of points to move around.
+ *
+ * Celebi's paper also stabilizes results and guarantees high quality by using starting centroids
+ * from Wu's quantization algorithm. See CelebiQuantizer for more info.
+ */
+public class WSMeansQuantizer implements Quantizer {
+    Mean[] mMeans;
+    private final Map<Integer, Integer> mCountByColor = new HashMap<>();
+    private final Map<Integer, Integer> mMeanIndexByColor = new HashMap<>();
+    private final Set<Integer> mUniqueColors = new HashSet<>();
+    private final List<Palette.Swatch> mSwatches = new ArrayList<>();
+    private final CentroidProvider mCentroidProvider;
+
+    public WSMeansQuantizer(
+            float[][] means, CentroidProvider centroidProvider, int[] pixels, int maxColors) {
+        if (pixels == null) {
+            pixels = new int[]{};
+        }
+        mCentroidProvider = centroidProvider;
+        mMeans = new Mean[maxColors];
+        for (int i = 0; i < means.length; i++) {
+            mMeans[i] = new Mean(means[i]);
+        }
+
+        if (maxColors > means.length) {
+            int randomMeansToCreate = maxColors - means.length;
+            for (int i = 0; i < randomMeansToCreate; i++) {
+                mMeans[means.length + i] = new Mean(100);
+            }
+        }
+
+        for (int pixel : pixels) {
+            Integer currentCount = mCountByColor.get(pixel);
+            if (currentCount == null) {
+                currentCount = 0;
+                mUniqueColors.add(pixel);
+            }
+            mCountByColor.put(pixel, currentCount + 1);
+        }
+        for (int color : mUniqueColors) {
+            int closestMeanIndex = -1;
+            double closestMeanDistance = -1;
+            float[] centroid = mCentroidProvider.getCentroid(color);
+            for (int i = 0; i < mMeans.length; i++) {
+                double distance = mCentroidProvider.distance(centroid, mMeans[i].center);
+                if (closestMeanIndex == -1 || distance < closestMeanDistance) {
+                    closestMeanIndex = i;
+                    closestMeanDistance = distance;
+                }
+            }
+            mMeanIndexByColor.put(color, closestMeanIndex);
+        }
+
+        if (pixels.length == 0) {
+            return;
+        }
+
+        predict(maxColors, 0);
+    }
+
+    /** Create starting centroids for K-means from a set of colors. */
+    public static float[][] createStartingCentroids(CentroidProvider centroidProvider,
+            List<Palette.Swatch> swatches) {
+        float[][] startingCentroids = new float[swatches.size()][];
+        for (int i = 0; i < swatches.size(); i++) {
+            startingCentroids[i] = centroidProvider.getCentroid(swatches.get(i).getInt());
+        }
+        return startingCentroids;
+    }
+
+    /** Create random starting centroids for K-means. */
+    public static float[][] randomMeans(int maxColors, int upperBound) {
+        float[][] means = new float[maxColors][];
+        for (int i = 0; i < maxColors; i++) {
+            means[i] = new Mean(upperBound).center;
+        }
+        return means;
+    }
+
+
+    @Override
+    public void quantize(int[] pixels, int maxColors) {
+
+    }
+
+    @Override
+    public List<Palette.Swatch> getQuantizedColors() {
+        return mSwatches;
+    }
+
+    private void predict(int maxColors, int iterationsCompleted) {
+        double[][] centroidDistance = new double[maxColors][maxColors];
+        for (int i = 0; i <= maxColors; i++) {
+            for (int j = i + 1; j < maxColors; j++) {
+                float[] meanI = mMeans[i].center;
+                float[] meanJ = mMeans[j].center;
+                double distance = mCentroidProvider.distance(meanI, meanJ);
+                centroidDistance[i][j] = distance;
+                centroidDistance[j][i] = distance;
+            }
+        }
+
+        // Construct a K×K matrix M in which row i is a permutation of
+        // 1,2,…,K that represents the clusters in increasing order of
+        // distance of their centers from ci;
+        int[][] distanceMatrix = new int[maxColors][maxColors];
+        for (int i = 0; i < maxColors; i++) {
+            double[] distancesFromIToAnotherMean = centroidDistance[i];
+            double[] sortedByDistanceAscending = distancesFromIToAnotherMean.clone();
+            Arrays.sort(sortedByDistanceAscending);
+            int[] outputRow = new int[maxColors];
+            for (int j = 0; j < maxColors; j++) {
+                outputRow[j] = findIndex(distancesFromIToAnotherMean, sortedByDistanceAscending[j]);
+            }
+            distanceMatrix[i] = outputRow;
+        }
+
+        //   for (i=1;i≤N′;i=i+ 1) do
+        //   Let Sp be the cluster that xi was assigned to in the previous
+        //   iteration;
+        //   p=m[i];
+        //   min_dist=prev_dist=jjxi−cpjj2;
+        boolean anyColorMoved = false;
+        for (int intColor : mUniqueColors) {
+            float[] color = mCentroidProvider.getCentroid(intColor);
+            int indexOfCurrentMean = mMeanIndexByColor.get(intColor);
+            Mean currentMean = mMeans[indexOfCurrentMean];
+            double minDistance = mCentroidProvider.distance(color, currentMean.center);
+            for (int j = 1; j < maxColors; j++) {
+                int indexOfClusterFromCurrentToJ = distanceMatrix[indexOfCurrentMean][j];
+                double distanceBetweenJAndCurrent =
+                        centroidDistance[indexOfCurrentMean][indexOfClusterFromCurrentToJ];
+                if (distanceBetweenJAndCurrent >= (4 * minDistance)) {
+                    break;
+                }
+                double distanceBetweenJAndColor = mCentroidProvider.distance(mMeans[j].center,
+                        color);
+                if (distanceBetweenJAndColor < minDistance) {
+                    minDistance = distanceBetweenJAndColor;
+                    mMeanIndexByColor.remove(intColor);
+                    mMeanIndexByColor.put(intColor, j);
+                    anyColorMoved = true;
+                }
+            }
+        }
+
+        List<MeanBucket> buckets = new ArrayList<>();
+        for (int i = 0; i < maxColors; i++) {
+            buckets.add(new MeanBucket());
+        }
+
+        for (int intColor : mUniqueColors) {
+            int meanIndex = mMeanIndexByColor.get(intColor);
+            MeanBucket meanBucket = buckets.get(meanIndex);
+            meanBucket.add(mCentroidProvider.getCentroid(intColor), intColor,
+                    mCountByColor.get(intColor));
+        }
+
+        List<Palette.Swatch> swatches = new ArrayList<>();
+        boolean done = !anyColorMoved && iterationsCompleted > 0 || iterationsCompleted >= 100;
+        if (done) {
+            for (int i = 0; i < buckets.size(); i++) {
+                MeanBucket a = buckets.get(i);
+                if (a.mCount <= 0) {
+                    continue;
+                }
+                List<MeanBucket> bucketsToMerge = new ArrayList<>();
+                for (int j = i + 1; j < buckets.size(); j++) {
+                    MeanBucket b = buckets.get(j);
+                    if (b.mCount == 0) {
+                        continue;
+                    }
+                    float[] bCentroid = b.getCentroid();
+                    assert (a.mCount > 0);
+                    assert (a.getCentroid() != null);
+
+                    assert (bCentroid != null);
+                    if (mCentroidProvider.distance(a.getCentroid(), b.getCentroid()) < 5) {
+                        bucketsToMerge.add(b);
+                    }
+                }
+
+                for (MeanBucket bucketToMerge : bucketsToMerge) {
+                    float[] centroid = bucketToMerge.getCentroid();
+                    a.add(centroid, mCentroidProvider.getColor(centroid), bucketToMerge.mCount);
+                    buckets.remove(bucketToMerge);
+                }
+            }
+
+            for (MeanBucket bucket : buckets) {
+                float[] centroid = bucket.getCentroid();
+                if (centroid == null) {
+                    continue;
+                }
+
+                int rgb = mCentroidProvider.getColor(centroid);
+                swatches.add(new Palette.Swatch(rgb, bucket.mCount));
+                mSwatches.clear();
+                mSwatches.addAll(swatches);
+            }
+        } else {
+            List<MeanBucket> emptyBuckets = new ArrayList<>();
+            for (int i = 0; i < buckets.size(); i++) {
+                MeanBucket bucket = buckets.get(i);
+                if ((bucket.getCentroid() == null) || (bucket.mCount == 0)) {
+                    emptyBuckets.add(bucket);
+                    for (Integer color : mUniqueColors) {
+                        int meanIndex = mMeanIndexByColor.get(color);
+                        if (meanIndex > i) {
+                            mMeanIndexByColor.put(color, meanIndex--);
+                        }
+                    }
+                }
+            }
+
+            Mean[] newMeans = new Mean[buckets.size()];
+            for (int i = 0; i < buckets.size(); i++) {
+                float[] centroid = buckets.get(i).getCentroid();
+                newMeans[i] = new Mean(centroid);
+            }
+
+            predict(buckets.size(), iterationsCompleted + 1);
+        }
+
+    }
+
+    private static int findIndex(double[] list, double element) {
+        for (int i = 0; i < list.length; i++) {
+            if (list[i] == element) {
+                return i;
+            }
+        }
+        throw new IllegalArgumentException("Element not in list");
+    }
+}
diff --git a/core/java/com/android/internal/graphics/palette/WuQuantizer.java b/core/java/com/android/internal/graphics/palette/WuQuantizer.java
new file mode 100644
index 0000000..01e45f6
--- /dev/null
+++ b/core/java/com/android/internal/graphics/palette/WuQuantizer.java
@@ -0,0 +1,442 @@
+/*
+ * 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.graphics.palette;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+// All reference Wu implementations are based on the original C code by Wu.
+// Comments on methods are the same as in the original implementation, and the comment below
+// is the original class header.
+
+/**
+ * Wu's Color Quantizer (v. 2) (see Graphics Gems vol. II, pp. 126-133) Author: Xiaolin Wu
+ *
+ * <p>Algorithm: Greedy orthogonal bipartition of RGB space for variance minimization aided by
+ * inclusion-exclusion tricks. For speed no nearest neighbor search is done. Slightly better
+ * performance can be expected by more sophisticated but more expensive versions.
+ */
+public class WuQuantizer implements Quantizer {
+    private static final int MAX_COLORS = 256;
+    private static final int RED = 2;
+    private static final int GREEN = 1;
+    private static final int BLUE = 0;
+
+    private static final int QUANT_SIZE = 33;
+    private final List<Palette.Swatch> mSwatches = new ArrayList<>();
+
+    @Override
+    public List<Palette.Swatch> getQuantizedColors() {
+        return mSwatches;
+    }
+
+    private static final class Box {
+        int mR0; /* min value, exclusive */
+        int mR1; /* max value, inclusive */
+        int mG0;
+        int mG1;
+        int mB0;
+        int mB1;
+        int mVol;
+    }
+
+    private final int mSize; /* image size, in bytes. */
+    private int mMaxColors;
+    private int[] mQadd;
+    private final int[] mPixels;
+
+    private final double[][][] mM2 = new double[QUANT_SIZE][QUANT_SIZE][QUANT_SIZE];
+    private final long[][][] mWt = new long[QUANT_SIZE][QUANT_SIZE][QUANT_SIZE];
+    private final long[][][] mMr = new long[QUANT_SIZE][QUANT_SIZE][QUANT_SIZE];
+    private final long[][][] mMg = new long[QUANT_SIZE][QUANT_SIZE][QUANT_SIZE];
+    private final long[][][] mMb = new long[QUANT_SIZE][QUANT_SIZE][QUANT_SIZE];
+
+    public WuQuantizer(int[] pixels, int maxColorCount) {
+        if (pixels == null) {
+            pixels = new int[]{};
+        }
+        this.mPixels = pixels;
+        this.mSize = pixels.length;
+    }
+
+    @Override
+    public void quantize(int[] colors, int maxColorCount) {
+        // All of the sample Wu implementations are reimplementations of a snippet of C code from
+        // the early 90s. They all cap the maximum # of colors at 256, and it is impossible to tell
+        // if this is a requirement, a consequence of QUANT_SIZE, or arbitrary.
+        this.mMaxColors = Math.min(MAX_COLORS, maxColorCount);
+        Box[] cube = new Box[mMaxColors];
+        int red, green, blue;
+
+        int next, i, k;
+        long weight;
+        double[] vv = new double[mMaxColors];
+        double temp;
+
+        compute3DHistogram(mWt, mMr, mMg, mMb, mM2);
+        computeMoments(mWt, mMr, mMg, mMb, mM2);
+
+        for (i = 0; i < mMaxColors; i++) {
+            cube[i] = new Box();
+        }
+
+        cube[0].mR0 = cube[0].mG0 = cube[0].mB0 = 0;
+        cube[0].mR1 = cube[0].mG1 = cube[0].mB1 = QUANT_SIZE - 1;
+        next = 0;
+
+        for (i = 1; i < mMaxColors; ++i) {
+            if (cut(cube[next], cube[i])) {
+                vv[next] = (cube[next].mVol > 1) ? getVariance(cube[next]) : 0.0f;
+                vv[i] = (cube[i].mVol > 1) ? getVariance(cube[i]) : 0.0f;
+            } else {
+                vv[next] = 0.0f;
+                i--;
+            }
+            next = 0;
+            temp = vv[0];
+            for (k = 1; k <= i; ++k) {
+                if (vv[k] > temp) {
+                    temp = vv[k];
+                    next = k;
+                }
+            }
+            if (temp <= 0.0f) {
+                break;
+            }
+        }
+
+        for (k = 0; k < mMaxColors; ++k) {
+            weight = getVolume(cube[k], mWt);
+            if (weight > 0) {
+                red = (int) (getVolume(cube[k], mMr) / weight);
+                green = (int) (getVolume(cube[k], mMg) / weight);
+                blue = (int) (getVolume(cube[k], mMb) / weight);
+                colors[k] = ((red & 0x0ff) << 16) | ((green & 0x0ff) << 8) | (blue & 0x0ff);
+            } else {
+                colors[k] = 0;
+            }
+        }
+
+        int bitsPerPixel = 0;
+        while ((1 << bitsPerPixel) < mMaxColors) {
+            bitsPerPixel++;
+        }
+
+        List<Palette.Swatch> swatches = new ArrayList<>();
+        for (int l = 0; l < k; l++) {
+            int pixel = colors[l];
+            if (pixel == 0) {
+                continue;
+            }
+            swatches.add(new Palette.Swatch(pixel, 0));
+        }
+        mSwatches.clear();
+        mSwatches.addAll(swatches);
+    }
+
+    /* Histogram is in elements 1..HISTSIZE along each axis,
+     * element 0 is for base or marginal value
+     * NB: these must start out 0!
+     */
+    private void compute3DHistogram(
+            long[][][] vwt, long[][][] vmr, long[][][] vmg, long[][][] vmb, double[][][] m2) {
+        // build 3-D color histogram of counts, r/g/b, and c^2
+        int r, g, b;
+        int i;
+        int inr;
+        int ing;
+        int inb;
+        int[] table = new int[256];
+
+        for (i = 0; i < 256; i++) {
+            table[i] = i * i;
+        }
+
+        mQadd = new int[mSize];
+
+        for (i = 0; i < mSize; ++i) {
+            int rgb = mPixels[i];
+            // Skip less than opaque pixels. They're not meaningful in the context of palette
+            // generation for UI schemes.
+            if ((rgb >>> 24) < 0xff) {
+                continue;
+            }
+            r = ((rgb >> 16) & 0xff);
+            g = ((rgb >> 8) & 0xff);
+            b = (rgb & 0xff);
+            inr = (r >> 3) + 1;
+            ing = (g >> 3) + 1;
+            inb = (b >> 3) + 1;
+            mQadd[i] = (inr << 10) + (inr << 6) + inr + (ing << 5) + ing + inb;
+            /*[inr][ing][inb]*/
+            ++vwt[inr][ing][inb];
+            vmr[inr][ing][inb] += r;
+            vmg[inr][ing][inb] += g;
+            vmb[inr][ing][inb] += b;
+            m2[inr][ing][inb] += table[r] + table[g] + table[b];
+        }
+    }
+
+    /* At conclusion of the histogram step, we can interpret
+     *   wt[r][g][b] = sum over voxel of P(c)
+     *   mr[r][g][b] = sum over voxel of r*P(c)  ,  similarly for mg, mb
+     *   m2[r][g][b] = sum over voxel of c^2*P(c)
+     * Actually each of these should be divided by 'size' to give the usual
+     * interpretation of P() as ranging from 0 to 1, but we needn't do that here.
+     *
+     * We now convert histogram into moments so that we can rapidly calculate
+     * the sums of the above quantities over any desired box.
+     */
+    private void computeMoments(
+            long[][][] vwt, long[][][] vmr, long[][][] vmg, long[][][] vmb, double[][][] m2) {
+        /* compute cumulative moments. */
+        int i, r, g, b;
+        int line, line_r, line_g, line_b;
+        int[] area = new int[QUANT_SIZE];
+        int[] area_r = new int[QUANT_SIZE];
+        int[] area_g = new int[QUANT_SIZE];
+        int[] area_b = new int[QUANT_SIZE];
+        double line2;
+        double[] area2 = new double[QUANT_SIZE];
+
+        for (r = 1; r < QUANT_SIZE; ++r) {
+            for (i = 0; i < QUANT_SIZE; ++i) {
+                area2[i] = area[i] = area_r[i] = area_g[i] = area_b[i] = 0;
+            }
+            for (g = 1; g < QUANT_SIZE; ++g) {
+                line2 = line = line_r = line_g = line_b = 0;
+                for (b = 1; b < QUANT_SIZE; ++b) {
+                    line += vwt[r][g][b];
+                    line_r += vmr[r][g][b];
+                    line_g += vmg[r][g][b];
+                    line_b += vmb[r][g][b];
+                    line2 += m2[r][g][b];
+
+                    area[b] += line;
+                    area_r[b] += line_r;
+                    area_g[b] += line_g;
+                    area_b[b] += line_b;
+                    area2[b] += line2;
+
+                    vwt[r][g][b] = vwt[r - 1][g][b] + area[b];
+                    vmr[r][g][b] = vmr[r - 1][g][b] + area_r[b];
+                    vmg[r][g][b] = vmg[r - 1][g][b] + area_g[b];
+                    vmb[r][g][b] = vmb[r - 1][g][b] + area_b[b];
+                    m2[r][g][b] = m2[r - 1][g][b] + area2[b];
+                }
+            }
+        }
+    }
+
+    private long getVolume(Box cube, long[][][] mmt) {
+        /* Compute sum over a box of any given statistic */
+        return (mmt[cube.mR1][cube.mG1][cube.mB1]
+                - mmt[cube.mR1][cube.mG1][cube.mB0]
+                - mmt[cube.mR1][cube.mG0][cube.mB1]
+                + mmt[cube.mR1][cube.mG0][cube.mB0]
+                - mmt[cube.mR0][cube.mG1][cube.mB1]
+                + mmt[cube.mR0][cube.mG1][cube.mB0]
+                + mmt[cube.mR0][cube.mG0][cube.mB1]
+                - mmt[cube.mR0][cube.mG0][cube.mB0]);
+    }
+
+    /* The next two routines allow a slightly more efficient calculation
+     * of Vol() for a proposed subbox of a given box.  The sum of Top()
+     * and Bottom() is the Vol() of a subbox split in the given direction
+     * and with the specified new upper bound.
+     */
+    private long getBottom(Box cube, int dir, long[][][] mmt) {
+        /* Compute part of Vol(cube, mmt) that doesn't depend on r1, g1, or b1 */
+        /* (depending on dir) */
+        switch (dir) {
+            case RED:
+                return (-mmt[cube.mR0][cube.mG1][cube.mB1]
+                        + mmt[cube.mR0][cube.mG1][cube.mB0]
+                        + mmt[cube.mR0][cube.mG0][cube.mB1]
+                        - mmt[cube.mR0][cube.mG0][cube.mB0]);
+            case GREEN:
+                return (-mmt[cube.mR1][cube.mG0][cube.mB1]
+                        + mmt[cube.mR1][cube.mG0][cube.mB0]
+                        + mmt[cube.mR0][cube.mG0][cube.mB1]
+                        - mmt[cube.mR0][cube.mG0][cube.mB0]);
+            case BLUE:
+                return (-mmt[cube.mR1][cube.mG1][cube.mB0]
+                        + mmt[cube.mR1][cube.mG0][cube.mB0]
+                        + mmt[cube.mR0][cube.mG1][cube.mB0]
+                        - mmt[cube.mR0][cube.mG0][cube.mB0]);
+            default:
+                return 0;
+        }
+    }
+
+    private long getTop(Box cube, int dir, int pos, long[][][] mmt) {
+        /* Compute remainder of Vol(cube, mmt), substituting pos for */
+        /* r1, g1, or b1 (depending on dir) */
+        switch (dir) {
+            case RED:
+                return (mmt[pos][cube.mG1][cube.mB1]
+                        - mmt[pos][cube.mG1][cube.mB0]
+                        - mmt[pos][cube.mG0][cube.mB1]
+                        + mmt[pos][cube.mG0][cube.mB0]);
+            case GREEN:
+                return (mmt[cube.mR1][pos][cube.mB1]
+                        - mmt[cube.mR1][pos][cube.mB0]
+                        - mmt[cube.mR0][pos][cube.mB1]
+                        + mmt[cube.mR0][pos][cube.mB0]);
+            case BLUE:
+                return (mmt[cube.mR1][cube.mG1][pos]
+                        - mmt[cube.mR1][cube.mG0][pos]
+                        - mmt[cube.mR0][cube.mG1][pos]
+                        + mmt[cube.mR0][cube.mG0][pos]);
+            default:
+                return 0;
+        }
+    }
+
+    private double getVariance(Box cube) {
+        /* Compute the weighted variance of a box */
+        /* NB: as with the raw statistics, this is really the variance * size */
+        double dr, dg, db, xx;
+        dr = getVolume(cube, mMr);
+        dg = getVolume(cube, mMg);
+        db = getVolume(cube, mMb);
+        xx =
+                mM2[cube.mR1][cube.mG1][cube.mB1]
+                        - mM2[cube.mR1][cube.mG1][cube.mB0]
+                        - mM2[cube.mR1][cube.mG0][cube.mB1]
+                        + mM2[cube.mR1][cube.mG0][cube.mB0]
+                        - mM2[cube.mR0][cube.mG1][cube.mB1]
+                        + mM2[cube.mR0][cube.mG1][cube.mB0]
+                        + mM2[cube.mR0][cube.mG0][cube.mB1]
+                        - mM2[cube.mR0][cube.mG0][cube.mB0];
+        return xx - (dr * dr + dg * dg + db * db) / getVolume(cube, mWt);
+    }
+
+    /* We want to minimize the sum of the variances of two subboxes.
+     * The sum(c^2) terms can be ignored since their sum over both subboxes
+     * is the same (the sum for the whole box) no matter where we split.
+     * The remaining terms have a minus sign in the variance formula,
+     * so we drop the minus sign and MAXIMIZE the sum of the two terms.
+     */
+    private double maximize(
+            Box cube,
+            int dir,
+            int first,
+            int last,
+            int[] cut,
+            long wholeR,
+            long wholeG,
+            long wholeB,
+            long wholeW) {
+        long half_r, half_g, half_b, half_w;
+        long base_r, base_g, base_b, base_w;
+        int i;
+        double temp, max;
+
+        base_r = getBottom(cube, dir, mMr);
+        base_g = getBottom(cube, dir, mMg);
+        base_b = getBottom(cube, dir, mMb);
+        base_w = getBottom(cube, dir, mWt);
+
+        max = 0.0f;
+        cut[0] = -1;
+
+        for (i = first; i < last; ++i) {
+            half_r = base_r + getTop(cube, dir, i, mMr);
+            half_g = base_g + getTop(cube, dir, i, mMg);
+            half_b = base_b + getTop(cube, dir, i, mMb);
+            half_w = base_w + getTop(cube, dir, i, mWt);
+            /* now half_x is sum over lower half of box, if split at i */
+            if (half_w == 0) /* subbox could be empty of pixels! */ {
+                continue; /* never split into an empty box */
+            }
+            temp = (half_r * half_r + half_g * half_g + half_b * half_b) / (double) half_w;
+            half_r = wholeR - half_r;
+            half_g = wholeG - half_g;
+            half_b = wholeB - half_b;
+            half_w = wholeW - half_w;
+            if (half_w == 0) /* subbox could be empty of pixels! */ {
+                continue; /* never split into an empty box */
+            }
+            temp += (half_r * half_r + half_g * half_g + half_b * half_b) / (double) half_w;
+
+            if (temp > max) {
+                max = temp;
+                cut[0] = i;
+            }
+        }
+
+        return max;
+    }
+
+    private boolean cut(Box set1, Box set2) {
+        int dir;
+        int[] cutr = new int[1];
+        int[] cutg = new int[1];
+        int[] cutb = new int[1];
+        double maxr, maxg, maxb;
+        long whole_r, whole_g, whole_b, whole_w;
+
+        whole_r = getVolume(set1, mMr);
+        whole_g = getVolume(set1, mMg);
+        whole_b = getVolume(set1, mMb);
+        whole_w = getVolume(set1, mWt);
+
+        maxr = maximize(set1, RED, set1.mR0 + 1, set1.mR1, cutr, whole_r, whole_g, whole_b,
+                whole_w);
+        maxg = maximize(set1, GREEN, set1.mG0 + 1, set1.mG1, cutg, whole_r, whole_g, whole_b,
+                whole_w);
+        maxb = maximize(set1, BLUE, set1.mB0 + 1, set1.mB1, cutb, whole_r, whole_g, whole_b,
+                whole_w);
+
+        if (maxr >= maxg && maxr >= maxb) {
+            dir = RED;
+            if (cutr[0] < 0) return false; /* can't split the box */
+        } else if (maxg >= maxr && maxg >= maxb) {
+            dir = GREEN;
+        } else {
+            dir = BLUE;
+        }
+
+        set2.mR1 = set1.mR1;
+        set2.mG1 = set1.mG1;
+        set2.mB1 = set1.mB1;
+
+        switch (dir) {
+            case RED:
+                set2.mR0 = set1.mR1 = cutr[0];
+                set2.mG0 = set1.mG0;
+                set2.mB0 = set1.mB0;
+                break;
+            case GREEN:
+                set2.mG0 = set1.mG1 = cutg[0];
+                set2.mR0 = set1.mR0;
+                set2.mB0 = set1.mB0;
+                break;
+            case BLUE:
+                set2.mB0 = set1.mB1 = cutb[0];
+                set2.mR0 = set1.mR0;
+                set2.mG0 = set1.mG0;
+                break;
+        }
+        set1.mVol = (set1.mR1 - set1.mR0) * (set1.mG1 - set1.mG0) * (set1.mB1 - set1.mB0);
+        set2.mVol = (set2.mR1 - set2.mR0) * (set2.mG1 - set2.mG0) * (set2.mB1 - set2.mB0);
+
+        return true;
+    }
+}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
index c353de8..93374ba 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
@@ -228,6 +228,8 @@
                 return "HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR";
             case SoftInputShowHideReason.HIDE_REMOVE_CLIENT:
                 return "HIDE_REMOVE_CLIENT";
+            case SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY:
+                return "SHOW_RESTORE_IME_VISIBILITY";
             default:
                 return "Unknown=" + reason;
         }
diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
index 1553e2e..f1cdf2b 100644
--- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
+++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
@@ -49,7 +49,8 @@
         SoftInputShowHideReason.HIDE_RECENTS_ANIMATION,
         SoftInputShowHideReason.HIDE_BUBBLES,
         SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR,
-        SoftInputShowHideReason.HIDE_REMOVE_CLIENT})
+        SoftInputShowHideReason.HIDE_REMOVE_CLIENT,
+        SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY})
 public @interface SoftInputShowHideReason {
     /** Show soft input by {@link android.view.inputmethod.InputMethodManager#showSoftInput}. */
     int SHOW_SOFT_INPUT = 0;
@@ -167,4 +168,10 @@
      * Hide soft input when a {@link com.android.internal.view.IInputMethodClient} is removed.
      */
     int HIDE_REMOVE_CLIENT = 21;
+
+    /**
+     * Show soft input when the system invoking
+     * {@link com.android.server.wm.WindowManagerInternal#shouldRestoreImeVisibility}.
+     */
+    int SHOW_RESTORE_IME_VISIBILITY = 22;
 }
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index 342456a..33ee8f0 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -203,6 +203,9 @@
         Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId);
         mCancelled = true;
         removeObservers();
+        if (mListener != null) {
+            mListener.onNotifyCujEvents(mSession, InteractionJankMonitor.ACTION_SESSION_CANCEL);
+        }
     }
 
     @Override
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 0294ec3..fbc92c1 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -99,7 +99,7 @@
     private static final int DEFAULT_TRACE_THRESHOLD_FRAME_TIME_MILLIS = 64;
 
     public static final String ACTION_SESSION_BEGIN = ACTION_PREFIX + ".ACTION_SESSION_BEGIN";
-    public static final String ACTION_SESSION_END = ACTION_PREFIX + ".ACTION_SESSION_END";
+    public static final String ACTION_SESSION_CANCEL = ACTION_PREFIX + ".ACTION_SESSION_CANCEL";
     public static final String ACTION_METRICS_LOGGED = ACTION_PREFIX + ".ACTION_METRICS_LOGGED";
     public static final String BUNDLE_KEY_CUJ_NAME = ACTION_PREFIX + ".CUJ_NAME";
     public static final String BUNDLE_KEY_TIMESTAMP = ACTION_PREFIX + ".TIMESTAMP";
diff --git a/core/java/com/android/internal/net/NetworkUtilsInternal.java b/core/java/com/android/internal/net/NetworkUtilsInternal.java
index 571d7e7..052959a 100644
--- a/core/java/com/android/internal/net/NetworkUtilsInternal.java
+++ b/core/java/com/android/internal/net/NetworkUtilsInternal.java
@@ -22,6 +22,8 @@
 import android.annotation.NonNull;
 import android.system.Os;
 
+import java.io.FileDescriptor;
+
 /** @hide */
 public class NetworkUtilsInternal {
 
@@ -36,6 +38,20 @@
     public static native void setAllowNetworkingForProcess(boolean allowNetworking);
 
     /**
+     * Protect {@code fd} from VPN connections.  After protecting, data sent through
+     * this socket will go directly to the underlying network, so its traffic will not be
+     * forwarded through the VPN.
+     */
+    public static native boolean protectFromVpn(FileDescriptor fd);
+
+    /**
+     * Protect {@code socketfd} from VPN connections.  After protecting, data sent through
+     * this socket will go directly to the underlying network, so its traffic will not be
+     * forwarded through the VPN.
+     */
+    public static native boolean protectFromVpn(int socketfd);
+
+    /**
      * Returns true if the hostname is weakly validated.
      * @param hostname Name of host to validate.
      * @return True if it's a valid-ish hostname.
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index bdb65f3..879e0a8 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.os;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.BatteryStats;
 import android.os.Parcel;
 import android.os.StatFs;
@@ -61,6 +63,7 @@
     public static final String FILE_SUFFIX = ".bin";
     private static final int MIN_FREE_SPACE = 100 * 1024 * 1024;
 
+    @Nullable
     private final BatteryStatsImpl mStats;
     private final Parcel mHistoryBuffer;
     private final File mHistoryDir;
@@ -107,7 +110,8 @@
      * @param systemDir typically /data/system
      * @param historyBuffer The in-memory history buffer.
      */
-    public BatteryStatsHistory(BatteryStatsImpl stats, File systemDir, Parcel historyBuffer) {
+    public BatteryStatsHistory(@NonNull BatteryStatsImpl stats, File systemDir,
+            Parcel historyBuffer) {
         mStats = stats;
         mHistoryBuffer = historyBuffer;
         mHistoryDir = new File(systemDir, HISTORY_DIR);
@@ -149,11 +153,10 @@
     /**
      * Used when BatteryStatsImpl object is created from deserialization of a parcel,
      * such as Settings app or checkin file.
-     * @param stats BatteryStatsImpl object.
-     * @param historyBuffer the history buffer inside BatteryStatsImpl
+     * @param historyBuffer the history buffer
      */
-    public BatteryStatsHistory(BatteryStatsImpl stats, Parcel historyBuffer) {
-        mStats = stats;
+    public BatteryStatsHistory(Parcel historyBuffer) {
+        mStats = null;
         mHistoryDir = null;
         mHistoryBuffer = historyBuffer;
     }
@@ -184,10 +187,16 @@
      * create next history file.
      */
     public void startNextFile() {
+        if (mStats == null) {
+            Slog.wtf(TAG, "mStats should not be null when writing history");
+            return;
+        }
+
         if (mFileNumbers.isEmpty()) {
             Slog.wtf(TAG, "mFileNumbers should never be empty");
             return;
         }
+
         // The last number in mFileNumbers is the highest number. The next file number is highest
         // number plus one.
         final int next = mFileNumbers.get(mFileNumbers.size() - 1) + 1;
@@ -357,7 +366,7 @@
     private boolean skipHead(Parcel p) {
         p.setDataPosition(0);
         final int version = p.readInt();
-        if (version != mStats.VERSION) {
+        if (version != BatteryStatsImpl.VERSION) {
             return false;
         }
         // skip historyBaseTime field.
diff --git a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
new file mode 100644
index 0000000..1871ac5
--- /dev/null
+++ b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
@@ -0,0 +1,264 @@
+/*
+ * 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.os;
+
+import android.annotation.NonNull;
+import android.os.BatteryManager;
+import android.os.BatteryStats;
+import android.os.Parcel;
+import android.util.Slog;
+
+import java.util.List;
+
+/**
+ * An iterator for {@link BatteryStats.HistoryItem}'s.
+ */
+public class BatteryStatsHistoryIterator {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "BatteryStatsHistoryItr";
+    private final BatteryStatsHistory mBatteryStatsHistory;
+    private final BatteryStats.HistoryStepDetails mReadHistoryStepDetails =
+            new BatteryStats.HistoryStepDetails();
+    private final String[] mReadHistoryStrings;
+    private final int[] mReadHistoryUids;
+
+    public BatteryStatsHistoryIterator(@NonNull BatteryStatsHistory history,
+            @NonNull List<BatteryStats.HistoryTag> historyTagPool) {
+        mBatteryStatsHistory = history;
+
+        mBatteryStatsHistory.startIteratingHistory();
+
+        mReadHistoryStrings = new String[historyTagPool.size()];
+        mReadHistoryUids = new int[historyTagPool.size()];
+        for (int i = historyTagPool.size() - 1; i >= 0; i--) {
+            BatteryStats.HistoryTag tag = historyTagPool.get(i);
+            final int idx = tag.poolIdx;
+            mReadHistoryStrings[idx] = tag.string;
+            mReadHistoryUids[idx] = tag.uid;
+        }
+    }
+
+    /**
+     * Retrieves the next HistoryItem from battery history, if available. Returns false if there
+     * are no more items.
+     */
+    public boolean next(BatteryStats.HistoryItem out) {
+        Parcel p = mBatteryStatsHistory.getNextParcel(out);
+        if (p == null) {
+            mBatteryStatsHistory.finishIteratingHistory();
+            return false;
+        }
+
+        final long lastRealtimeMs = out.time;
+        final long lastWalltimeMs = out.currentTime;
+        readHistoryDelta(p, out);
+        if (out.cmd != BatteryStats.HistoryItem.CMD_CURRENT_TIME
+                && out.cmd != BatteryStats.HistoryItem.CMD_RESET && lastWalltimeMs != 0) {
+            out.currentTime = lastWalltimeMs + (out.time - lastRealtimeMs);
+        }
+        return true;
+    }
+
+    void readHistoryDelta(Parcel src, BatteryStats.HistoryItem cur) {
+        int firstToken = src.readInt();
+        int deltaTimeToken = firstToken & BatteryStatsImpl.DELTA_TIME_MASK;
+        cur.cmd = BatteryStats.HistoryItem.CMD_UPDATE;
+        cur.numReadInts = 1;
+        if (DEBUG) {
+            Slog.i(TAG, "READ DELTA: firstToken=0x" + Integer.toHexString(firstToken)
+                    + " deltaTimeToken=" + deltaTimeToken);
+        }
+
+        if (deltaTimeToken < BatteryStatsImpl.DELTA_TIME_ABS) {
+            cur.time += deltaTimeToken;
+        } else if (deltaTimeToken == BatteryStatsImpl.DELTA_TIME_ABS) {
+            cur.readFromParcel(src);
+            if (DEBUG) Slog.i(TAG, "READ DELTA: ABS time=" + cur.time);
+            return;
+        } else if (deltaTimeToken == BatteryStatsImpl.DELTA_TIME_INT) {
+            int delta = src.readInt();
+            cur.time += delta;
+            cur.numReadInts += 1;
+            if (DEBUG) Slog.i(TAG, "READ DELTA: time delta=" + delta + " new time=" + cur.time);
+        } else {
+            long delta = src.readLong();
+            if (DEBUG) Slog.i(TAG, "READ DELTA: time delta=" + delta + " new time=" + cur.time);
+            cur.time += delta;
+            cur.numReadInts += 2;
+        }
+
+        final int batteryLevelInt;
+        if ((firstToken & BatteryStatsImpl.DELTA_BATTERY_LEVEL_FLAG) != 0) {
+            batteryLevelInt = src.readInt();
+            readBatteryLevelInt(batteryLevelInt, cur);
+            cur.numReadInts += 1;
+            if (DEBUG) {
+                Slog.i(TAG, "READ DELTA: batteryToken=0x"
+                        + Integer.toHexString(batteryLevelInt)
+                        + " batteryLevel=" + cur.batteryLevel
+                        + " batteryTemp=" + cur.batteryTemperature
+                        + " batteryVolt=" + (int) cur.batteryVoltage);
+            }
+        } else {
+            batteryLevelInt = 0;
+        }
+
+        if ((firstToken & BatteryStatsImpl.DELTA_STATE_FLAG) != 0) {
+            int stateInt = src.readInt();
+            cur.states = (firstToken & BatteryStatsImpl.DELTA_STATE_MASK) | (stateInt
+                    & (~BatteryStatsImpl.STATE_BATTERY_MASK));
+            cur.batteryStatus = (byte) ((stateInt >> BatteryStatsImpl.STATE_BATTERY_STATUS_SHIFT)
+                    & BatteryStatsImpl.STATE_BATTERY_STATUS_MASK);
+            cur.batteryHealth = (byte) ((stateInt >> BatteryStatsImpl.STATE_BATTERY_HEALTH_SHIFT)
+                    & BatteryStatsImpl.STATE_BATTERY_HEALTH_MASK);
+            cur.batteryPlugType = (byte) ((stateInt >> BatteryStatsImpl.STATE_BATTERY_PLUG_SHIFT)
+                    & BatteryStatsImpl.STATE_BATTERY_PLUG_MASK);
+            switch (cur.batteryPlugType) {
+                case 1:
+                    cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_AC;
+                    break;
+                case 2:
+                    cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_USB;
+                    break;
+                case 3:
+                    cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
+                    break;
+            }
+            cur.numReadInts += 1;
+            if (DEBUG) {
+                Slog.i(TAG, "READ DELTA: stateToken=0x"
+                        + Integer.toHexString(stateInt)
+                        + " batteryStatus=" + cur.batteryStatus
+                        + " batteryHealth=" + cur.batteryHealth
+                        + " batteryPlugType=" + cur.batteryPlugType
+                        + " states=0x" + Integer.toHexString(cur.states));
+            }
+        } else {
+            cur.states = (firstToken & BatteryStatsImpl.DELTA_STATE_MASK) | (cur.states
+                    & (~BatteryStatsImpl.STATE_BATTERY_MASK));
+        }
+
+        if ((firstToken & BatteryStatsImpl.DELTA_STATE2_FLAG) != 0) {
+            cur.states2 = src.readInt();
+            if (DEBUG) {
+                Slog.i(TAG, "READ DELTA: states2=0x"
+                        + Integer.toHexString(cur.states2));
+            }
+        }
+
+        if ((firstToken & BatteryStatsImpl.DELTA_WAKELOCK_FLAG) != 0) {
+            int indexes = src.readInt();
+            int wakeLockIndex = indexes & 0xffff;
+            int wakeReasonIndex = (indexes >> 16) & 0xffff;
+            if (wakeLockIndex != 0xffff) {
+                cur.wakelockTag = cur.localWakelockTag;
+                readHistoryTag(wakeLockIndex, cur.wakelockTag);
+                if (DEBUG) {
+                    Slog.i(TAG, "READ DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx
+                            + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string);
+                }
+            } else {
+                cur.wakelockTag = null;
+            }
+            if (wakeReasonIndex != 0xffff) {
+                cur.wakeReasonTag = cur.localWakeReasonTag;
+                readHistoryTag(wakeReasonIndex, cur.wakeReasonTag);
+                if (DEBUG) {
+                    Slog.i(TAG, "READ DELTA: wakeReasonTag=#" + cur.wakeReasonTag.poolIdx
+                            + " " + cur.wakeReasonTag.uid + ":" + cur.wakeReasonTag.string);
+                }
+            } else {
+                cur.wakeReasonTag = null;
+            }
+            cur.numReadInts += 1;
+        } else {
+            cur.wakelockTag = null;
+            cur.wakeReasonTag = null;
+        }
+
+        if ((firstToken & BatteryStatsImpl.DELTA_EVENT_FLAG) != 0) {
+            cur.eventTag = cur.localEventTag;
+            final int codeAndIndex = src.readInt();
+            cur.eventCode = (codeAndIndex & 0xffff);
+            final int index = ((codeAndIndex >> 16) & 0xffff);
+            readHistoryTag(index, cur.eventTag);
+            cur.numReadInts += 1;
+            if (DEBUG) {
+                Slog.i(TAG, "READ DELTA: event=" + cur.eventCode + " tag=#"
+                        + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":"
+                        + cur.eventTag.string);
+            }
+        } else {
+            cur.eventCode = BatteryStats.HistoryItem.EVENT_NONE;
+        }
+
+        if ((batteryLevelInt & BatteryStatsImpl.BATTERY_DELTA_LEVEL_FLAG) != 0) {
+            cur.stepDetails = mReadHistoryStepDetails;
+            cur.stepDetails.readFromParcel(src);
+        } else {
+            cur.stepDetails = null;
+        }
+
+        if ((firstToken & BatteryStatsImpl.DELTA_BATTERY_CHARGE_FLAG) != 0) {
+            cur.batteryChargeUah = src.readInt();
+        }
+        cur.modemRailChargeMah = src.readDouble();
+        cur.wifiRailChargeMah = src.readDouble();
+    }
+
+    int getHistoryStringPoolSize() {
+        return mReadHistoryStrings.length;
+    }
+
+    int getHistoryStringPoolBytes() {
+        int totalChars = 0;
+        for (int i = mReadHistoryStrings.length - 1; i >= 0; i--) {
+            if (mReadHistoryStrings[i] != null) {
+                totalChars += mReadHistoryStrings[i].length() + 1;
+            }
+        }
+
+        // Each entry is a fixed 12 bytes: 4 for index, 4 for uid, 4 for string size
+        // Each string character is 2 bytes.
+        return (mReadHistoryStrings.length * 12) + (totalChars * 2);
+    }
+
+    String getHistoryTagPoolString(int index) {
+        return mReadHistoryStrings[index];
+    }
+
+    int getHistoryTagPoolUid(int index) {
+        return mReadHistoryUids[index];
+    }
+
+    private void readHistoryTag(int index, BatteryStats.HistoryTag tag) {
+        if (index < mReadHistoryStrings.length) {
+            tag.string = mReadHistoryStrings[index];
+            tag.uid = mReadHistoryUids[index];
+        } else {
+            tag.string = null;
+            tag.uid = 0;
+        }
+        tag.poolIdx = index;
+    }
+
+    private static void readBatteryLevelInt(int batteryLevelInt, BatteryStats.HistoryItem out) {
+        out.batteryLevel = (byte) ((batteryLevelInt & 0xfe000000) >>> 25);
+        out.batteryTemperature = (short) ((batteryLevelInt & 0x01ff8000) >>> 15);
+        out.batteryVoltage = (char) ((batteryLevelInt & 0x00007ffe) >>> 1);
+    }
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 1f8ffe0..73527d4 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -81,7 +81,6 @@
 import android.util.IntArray;
 import android.util.KeyValueListParser;
 import android.util.Log;
-import android.util.LogWriter;
 import android.util.LongSparseArray;
 import android.util.LongSparseLongArray;
 import android.util.MutableInt;
@@ -108,7 +107,6 @@
 import com.android.internal.power.MeasuredEnergyStats;
 import com.android.internal.power.MeasuredEnergyStats.StandardEnergyBucket;
 import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.XmlUtils;
 import com.android.net.module.util.NetworkCapabilitiesUtils;
@@ -164,7 +162,6 @@
     private static final boolean DEBUG_BINDER_STATS = false;
     private static final boolean DEBUG_MEMORY = false;
     private static final boolean DEBUG_HISTORY = false;
-    private static final boolean USE_OLD_HISTORY = false;   // for debugging.
 
     // TODO: remove "tcp" from network methods, since we measure total stats.
 
@@ -172,7 +169,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    static final int VERSION = 193 + (USE_OLD_HISTORY ? 1000 : 0);
+    static final int VERSION = 193;
 
     // The maximum number of names wakelocks we will keep track of
     // per uid; once the limit is reached, we batch the remaining wakelocks
@@ -740,15 +737,11 @@
     protected boolean mRecordingHistory = false;
     int mNumHistoryItems;
 
+    final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap<>();
     final Parcel mHistoryBuffer = Parcel.obtain();
     final HistoryItem mHistoryLastWritten = new HistoryItem();
     final HistoryItem mHistoryLastLastWritten = new HistoryItem();
-    final HistoryItem mHistoryReadTmp = new HistoryItem();
     final HistoryItem mHistoryAddTmp = new HistoryItem();
-    final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap<>();
-    String[] mReadHistoryStrings;
-    int[] mReadHistoryUids;
-    int mReadHistoryChars;
     int mNextHistoryTagIdx = 0;
     int mNumHistoryTagChars = 0;
     int mHistoryBufferLastPos = -1;
@@ -789,6 +782,7 @@
     private final HashMap<Integer, PowerForUid> mUidToPower = ENABLE_FOREGROUND_STATS_COLLECTION
             ? new HashMap<>() : null;
 
+    @NonNull
     final BatteryStatsHistory mBatteryStatsHistory;
 
     final HistoryItem mHistoryCur = new HistoryItem();
@@ -831,9 +825,9 @@
     long mCurStepStatSoftIrqTimeMs;
     long mCurStepStatIdleTimeMs;
 
+    private BatteryStatsHistoryIterator mBatteryStatsHistoryIterator;
     private HistoryItem mHistoryIterator;
     private boolean mReadOverflow;
-    private boolean mIteratingHistory;
 
     int mStartCount;
 
@@ -1197,7 +1191,7 @@
         mStatsFile = null;
         mCheckinFile = null;
         mDailyFile = null;
-        mBatteryStatsHistory = null;
+        mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer);
         mHandler = null;
         mPlatformIdleStateCallback = null;
         mMeasuredEnergyRetriever = null;
@@ -3244,17 +3238,6 @@
         return idx;
     }
 
-    private void readHistoryTag(int index, HistoryTag tag) {
-        if (index < mReadHistoryStrings.length) {
-            tag.string = mReadHistoryStrings[index];
-            tag.uid = mReadHistoryUids[index];
-        } else {
-            tag.string = null;
-            tag.uid = 0;
-        }
-        tag.poolIdx = index;
-    }
-
     /*
         The history delta format uses flags to denote further data in subsequent ints in the parcel.
 
@@ -3631,137 +3614,6 @@
         mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs;
     }
 
-    public void readHistoryDelta(Parcel src, HistoryItem cur) {
-        int firstToken = src.readInt();
-        int deltaTimeToken = firstToken&DELTA_TIME_MASK;
-        cur.cmd = HistoryItem.CMD_UPDATE;
-        cur.numReadInts = 1;
-        if (DEBUG) Slog.i(TAG, "READ DELTA: firstToken=0x" + Integer.toHexString(firstToken)
-                + " deltaTimeToken=" + deltaTimeToken);
-
-        if (deltaTimeToken < DELTA_TIME_ABS) {
-            cur.time += deltaTimeToken;
-        } else if (deltaTimeToken == DELTA_TIME_ABS) {
-            cur.readFromParcel(src);
-            if (DEBUG) Slog.i(TAG, "READ DELTA: ABS time=" + cur.time);
-            return;
-        } else if (deltaTimeToken == DELTA_TIME_INT) {
-            int delta = src.readInt();
-            cur.time += delta;
-            cur.numReadInts += 1;
-            if (DEBUG) Slog.i(TAG, "READ DELTA: time delta=" + delta + " new time=" + cur.time);
-        } else {
-            long delta = src.readLong();
-            if (DEBUG) Slog.i(TAG, "READ DELTA: time delta=" + delta + " new time=" + cur.time);
-            cur.time += delta;
-            cur.numReadInts += 2;
-        }
-
-        final int batteryLevelInt;
-        if ((firstToken&DELTA_BATTERY_LEVEL_FLAG) != 0) {
-            batteryLevelInt = src.readInt();
-            readBatteryLevelInt(batteryLevelInt, cur);
-            cur.numReadInts += 1;
-            if (DEBUG) Slog.i(TAG, "READ DELTA: batteryToken=0x"
-                    + Integer.toHexString(batteryLevelInt)
-                    + " batteryLevel=" + cur.batteryLevel
-                    + " batteryTemp=" + cur.batteryTemperature
-                    + " batteryVolt=" + (int)cur.batteryVoltage);
-        } else {
-            batteryLevelInt = 0;
-        }
-
-        if ((firstToken&DELTA_STATE_FLAG) != 0) {
-            int stateInt = src.readInt();
-            cur.states = (firstToken&DELTA_STATE_MASK) | (stateInt&(~STATE_BATTERY_MASK));
-            cur.batteryStatus = (byte)((stateInt>>STATE_BATTERY_STATUS_SHIFT)
-                    & STATE_BATTERY_STATUS_MASK);
-            cur.batteryHealth = (byte)((stateInt>>STATE_BATTERY_HEALTH_SHIFT)
-                    & STATE_BATTERY_HEALTH_MASK);
-            cur.batteryPlugType = (byte)((stateInt>>STATE_BATTERY_PLUG_SHIFT)
-                    & STATE_BATTERY_PLUG_MASK);
-            switch (cur.batteryPlugType) {
-                case 1:
-                    cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_AC;
-                    break;
-                case 2:
-                    cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_USB;
-                    break;
-                case 3:
-                    cur.batteryPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
-                    break;
-            }
-            cur.numReadInts += 1;
-            if (DEBUG) Slog.i(TAG, "READ DELTA: stateToken=0x"
-                    + Integer.toHexString(stateInt)
-                    + " batteryStatus=" + cur.batteryStatus
-                    + " batteryHealth=" + cur.batteryHealth
-                    + " batteryPlugType=" + cur.batteryPlugType
-                    + " states=0x" + Integer.toHexString(cur.states));
-        } else {
-            cur.states = (firstToken&DELTA_STATE_MASK) | (cur.states&(~STATE_BATTERY_MASK));
-        }
-
-        if ((firstToken&DELTA_STATE2_FLAG) != 0) {
-            cur.states2 = src.readInt();
-            if (DEBUG) Slog.i(TAG, "READ DELTA: states2=0x"
-                    + Integer.toHexString(cur.states2));
-        }
-
-        if ((firstToken&DELTA_WAKELOCK_FLAG) != 0) {
-            int indexes = src.readInt();
-            int wakeLockIndex = indexes&0xffff;
-            int wakeReasonIndex = (indexes>>16)&0xffff;
-            if (wakeLockIndex != 0xffff) {
-                cur.wakelockTag = cur.localWakelockTag;
-                readHistoryTag(wakeLockIndex, cur.wakelockTag);
-                if (DEBUG) Slog.i(TAG, "READ DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx
-                    + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string);
-            } else {
-                cur.wakelockTag = null;
-            }
-            if (wakeReasonIndex != 0xffff) {
-                cur.wakeReasonTag = cur.localWakeReasonTag;
-                readHistoryTag(wakeReasonIndex, cur.wakeReasonTag);
-                if (DEBUG) Slog.i(TAG, "READ DELTA: wakeReasonTag=#" + cur.wakeReasonTag.poolIdx
-                    + " " + cur.wakeReasonTag.uid + ":" + cur.wakeReasonTag.string);
-            } else {
-                cur.wakeReasonTag = null;
-            }
-            cur.numReadInts += 1;
-        } else {
-            cur.wakelockTag = null;
-            cur.wakeReasonTag = null;
-        }
-
-        if ((firstToken&DELTA_EVENT_FLAG) != 0) {
-            cur.eventTag = cur.localEventTag;
-            final int codeAndIndex = src.readInt();
-            cur.eventCode = (codeAndIndex&0xffff);
-            final int index = ((codeAndIndex>>16)&0xffff);
-            readHistoryTag(index, cur.eventTag);
-            cur.numReadInts += 1;
-            if (DEBUG) Slog.i(TAG, "READ DELTA: event=" + cur.eventCode + " tag=#"
-                    + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":"
-                    + cur.eventTag.string);
-        } else {
-            cur.eventCode = HistoryItem.EVENT_NONE;
-        }
-
-        if ((batteryLevelInt&BATTERY_DELTA_LEVEL_FLAG) != 0) {
-            cur.stepDetails = mReadHistoryStepDetails;
-            cur.stepDetails.readFromParcel(src);
-        } else {
-            cur.stepDetails = null;
-        }
-
-        if ((firstToken&DELTA_BATTERY_CHARGE_FLAG) != 0) {
-            cur.batteryChargeUah = src.readInt();
-        }
-        cur.modemRailChargeMah = src.readDouble();
-        cur.wifiRailChargeMah = src.readDouble();
-    }
-
     @Override
     public void commitCurrentHistoryBatchLocked() {
         mHistoryLastWritten.cmd = HistoryItem.CMD_NULL;
@@ -3873,7 +3725,7 @@
     }
 
     private void addHistoryBufferLocked(long elapsedRealtimeMs, byte cmd, HistoryItem cur) {
-        if (mIteratingHistory) {
+        if (mBatteryStatsHistoryIterator != null) {
             throw new IllegalStateException("Can't do this while iterating history!");
         }
         mHistoryBufferLastPos = mHistoryBuffer.dataPosition();
@@ -3917,44 +3769,6 @@
 
     void addHistoryRecordInnerLocked(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur) {
         addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, cur);
-
-        if (!USE_OLD_HISTORY) {
-            return;
-        }
-
-        if (!mHaveBatteryLevel || !mRecordingHistory) {
-            return;
-        }
-
-        // If the current time is basically the same as the last time,
-        // and no states have since the last recorded entry changed and
-        // are now resetting back to their original value, then just collapse
-        // into one record.
-        if (mHistoryEnd != null && mHistoryEnd.cmd == HistoryItem.CMD_UPDATE
-                && (mHistoryBaseTimeMs + elapsedRealtimeMs) < (mHistoryEnd.time + 1000)
-                && ((mHistoryEnd.states^cur.states)&mChangedStates&mActiveHistoryStates) == 0
-                && ((mHistoryEnd.states2^cur.states2)&mChangedStates2&mActiveHistoryStates2) == 0) {
-            // If the current is the same as the one before, then we no
-            // longer need the entry.
-            if (mHistoryLastEnd != null && mHistoryLastEnd.cmd == HistoryItem.CMD_UPDATE
-                    && (mHistoryBaseTimeMs + elapsedRealtimeMs) < (mHistoryEnd.time + 500)
-                    && mHistoryLastEnd.sameNonEvent(cur)) {
-                mHistoryLastEnd.next = null;
-                mHistoryEnd.next = mHistoryCache;
-                mHistoryCache = mHistoryEnd;
-                mHistoryEnd = mHistoryLastEnd;
-                mHistoryLastEnd = null;
-            } else {
-                mChangedStates |= mHistoryEnd.states^(cur.states&mActiveHistoryStates);
-                mChangedStates2 |= mHistoryEnd.states^(cur.states2&mActiveHistoryStates2);
-                mHistoryEnd.setTo(mHistoryEnd.time, HistoryItem.CMD_UPDATE, cur);
-            }
-            return;
-        }
-
-        mChangedStates = 0;
-        mChangedStates2 = 0;
-        addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_UPDATE, cur);
     }
 
     public void addHistoryEventLocked(long elapsedRealtimeMs, long uptimeMs, int code,
@@ -3992,15 +3806,6 @@
 
     void clearHistoryLocked() {
         if (DEBUG_HISTORY) Slog.i(TAG, "********** CLEARING HISTORY!");
-        if (USE_OLD_HISTORY) {
-            if (mHistory != null) {
-                mHistoryEnd.next = mHistoryCache;
-                mHistoryCache = mHistory;
-                mHistory = mHistoryLastEnd = mHistoryEnd = null;
-            }
-            mNumHistoryItems = 0;
-        }
-
         mHistoryBaseTimeMs = 0;
         mLastHistoryElapsedRealtimeMs = 0;
         mTrackRunningHistoryElapsedRealtimeMs = 0;
@@ -7965,16 +7770,14 @@
 
         /** Adds the given energy to the given standard energy bucket for this uid. */
         private void addEnergyToStandardBucketLocked(long energyDeltaUJ,
-                @StandardEnergyBucket int energyBucket, boolean accumulate) {
+                @StandardEnergyBucket int energyBucket) {
             getOrCreateMeasuredEnergyStatsLocked()
-                    .updateStandardBucket(energyBucket, energyDeltaUJ, accumulate);
+                    .updateStandardBucket(energyBucket, energyDeltaUJ);
         }
 
         /** Adds the given energy to the given custom energy bucket for this uid. */
-        private void addEnergyToCustomBucketLocked(long energyDeltaUJ, int energyBucket,
-                boolean accumulate) {
-            getOrCreateMeasuredEnergyStatsLocked()
-                    .updateCustomBucket(energyBucket, energyDeltaUJ, accumulate);
+        private void addEnergyToCustomBucketLocked(long energyDeltaUJ, int energyBucket) {
+            getOrCreateMeasuredEnergyStatsLocked().updateCustomBucket(energyBucket, energyDeltaUJ);
         }
 
         /**
@@ -10733,7 +10536,7 @@
 
         if (systemDir == null) {
             mStatsFile = null;
-            mBatteryStatsHistory = new BatteryStatsHistory(this, mHistoryBuffer);
+            mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer);
         } else {
             mStatsFile = new AtomicFile(new File(systemDir, "batterystats.bin"));
             mBatteryStatsHistory = new BatteryStatsHistory(this, systemDir, mHistoryBuffer);
@@ -10855,7 +10658,7 @@
         mExternalSync = null;
         mConstants = new Constants(mHandler);
         clearHistoryLocked();
-        mBatteryStatsHistory = new BatteryStatsHistory(this, mHistoryBuffer);
+        mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer);
         readFromParcel(p);
         mPlatformIdleStateCallback = null;
         mMeasuredEnergyRetriever = null;
@@ -11222,60 +11025,6 @@
         return mNextMaxDailyDeadlineMs;
     }
 
-    @Override
-    public boolean startIteratingOldHistoryLocked() {
-        if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
-                + " pos=" + mHistoryBuffer.dataPosition());
-        if ((mHistoryIterator = mHistory) == null) {
-            return false;
-        }
-        mHistoryBuffer.setDataPosition(0);
-        mHistoryReadTmp.clear();
-        mReadOverflow = false;
-        mIteratingHistory = true;
-        return true;
-    }
-
-    @Override
-    public boolean getNextOldHistoryLocked(HistoryItem out) {
-        boolean end = mHistoryBuffer.dataPosition() >= mHistoryBuffer.dataSize();
-        if (!end) {
-            readHistoryDelta(mHistoryBuffer, mHistoryReadTmp);
-            mReadOverflow |= mHistoryReadTmp.cmd == HistoryItem.CMD_OVERFLOW;
-        }
-        HistoryItem cur = mHistoryIterator;
-        if (cur == null) {
-            if (!mReadOverflow && !end) {
-                Slog.w(TAG, "Old history ends before new history!");
-            }
-            return false;
-        }
-        out.setTo(cur);
-        mHistoryIterator = cur.next;
-        if (!mReadOverflow) {
-            if (end) {
-                Slog.w(TAG, "New history ends before old history!");
-            } else if (!out.same(mHistoryReadTmp)) {
-                PrintWriter pw = new FastPrintWriter(new LogWriter(android.util.Log.WARN, TAG));
-                pw.println("Histories differ!");
-                pw.println("Old history:");
-                (new HistoryPrinter()).printNextItem(pw, out, 0, false, true);
-                pw.println("New history:");
-                (new HistoryPrinter()).printNextItem(pw, mHistoryReadTmp, 0, false,
-                        true);
-                pw.flush();
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public void finishIteratingOldHistoryLocked() {
-        mIteratingHistory = false;
-        mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
-        mHistoryIterator = null;
-    }
-
     public int getHistoryTotalSize() {
         return mConstants.MAX_HISTORY_BUFFER * mConstants.MAX_HISTORY_FILES;
     }
@@ -11287,67 +11036,55 @@
     @Override
     @UnsupportedAppUsage
     public boolean startIteratingHistoryLocked() {
-        mBatteryStatsHistory.startIteratingHistory();
         mReadOverflow = false;
-        mIteratingHistory = true;
-        mReadHistoryStrings = new String[mHistoryTagPool.size()];
-        mReadHistoryUids = new int[mHistoryTagPool.size()];
-        mReadHistoryChars = 0;
-        for (HashMap.Entry<HistoryTag, Integer> ent : mHistoryTagPool.entrySet()) {
-            final HistoryTag tag = ent.getKey();
-            final int idx = ent.getValue();
-            mReadHistoryStrings[idx] = tag.string;
-            mReadHistoryUids[idx] = tag.uid;
-            mReadHistoryChars += tag.string.length() + 1;
-        }
+        mBatteryStatsHistoryIterator = createBatteryStatsHistoryIterator();
         return true;
     }
 
+    /**
+     * Creates an iterator for battery stats history.
+     */
+    @VisibleForTesting
+    public BatteryStatsHistoryIterator createBatteryStatsHistoryIterator() {
+        ArrayList<HistoryTag> tags = new ArrayList<>(mHistoryTagPool.size());
+        for (Map.Entry<HistoryTag, Integer> entry: mHistoryTagPool.entrySet()) {
+            final HistoryTag tag = entry.getKey();
+            tag.poolIdx = entry.getValue();
+            tags.add(tag);
+        }
+
+        return new BatteryStatsHistoryIterator(mBatteryStatsHistory, tags);
+    }
+
     @Override
     public int getHistoryStringPoolSize() {
-        return mReadHistoryStrings.length;
+        return mBatteryStatsHistoryIterator.getHistoryStringPoolSize();
     }
 
     @Override
     public int getHistoryStringPoolBytes() {
-        // Each entry is a fixed 12 bytes: 4 for index, 4 for uid, 4 for string size
-        // Each string character is 2 bytes.
-        return (mReadHistoryStrings.length * 12) + (mReadHistoryChars * 2);
+        return mBatteryStatsHistoryIterator.getHistoryStringPoolBytes();
     }
 
     @Override
     public String getHistoryTagPoolString(int index) {
-        return mReadHistoryStrings[index];
+        return mBatteryStatsHistoryIterator.getHistoryTagPoolString(index);
     }
 
     @Override
     public int getHistoryTagPoolUid(int index) {
-        return mReadHistoryUids[index];
+        return mBatteryStatsHistoryIterator.getHistoryTagPoolUid(index);
     }
 
     @Override
     @UnsupportedAppUsage
     public boolean getNextHistoryLocked(HistoryItem out) {
-        Parcel p = mBatteryStatsHistory.getNextParcel(out);
-        if (p == null) {
-            return false;
-        }
-        final long lastRealtimeMs = out.time;
-        final long lastWalltimeMs = out.currentTime;
-        readHistoryDelta(p, out);
-        if (out.cmd != HistoryItem.CMD_CURRENT_TIME
-                && out.cmd != HistoryItem.CMD_RESET && lastWalltimeMs != 0) {
-            out.currentTime = lastWalltimeMs + (out.time - lastRealtimeMs);
-        }
-        return true;
+        return mBatteryStatsHistoryIterator.next(out);
     }
 
     @Override
     public void finishIteratingHistoryLocked() {
-        mBatteryStatsHistory.finishIteratingHistory();
-        mIteratingHistory = false;
-        mReadHistoryStrings = null;
-        mReadHistoryUids = null;
+        mBatteryStatsHistoryIterator = null;
     }
 
     @Override
@@ -12468,7 +12205,7 @@
             return;
         }
 
-        mGlobalMeasuredEnergyStats.updateStandardBucket(energyBucket, energyUJ, true);
+        mGlobalMeasuredEnergyStats.updateStandardBucket(energyBucket, energyUJ);
 
         // Now we blame individual apps, but only if the display was ON.
         if (energyBucket != MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON) {
@@ -12506,7 +12243,7 @@
             final long appDisplayEnergyMJ =
                     (totalDisplayEnergyMJ * fgTimeMs + (totalFgTimeMs / 2))
                     / totalFgTimeMs;
-            uid.addEnergyToStandardBucketLocked(appDisplayEnergyMJ * 1000, energyBucket, true);
+            uid.addEnergyToStandardBucketLocked(appDisplayEnergyMJ * 1000, energyBucket);
 
             // To mitigate round-off errors, remove this app from numerator & denominator totals
             totalDisplayEnergyMJ -= appDisplayEnergyMJ;
@@ -12520,6 +12257,7 @@
      * @param totalEnergyUJ energy (microjoules) used for this bucket since this was last called.
      * @param uidEnergies map of uid->energy (microjoules) for this bucket since last called.
      *                    Data inside uidEnergies will not be modified (treated immutable).
+     *                    Uids not already known to BatteryStats will be ignored.
      */
     public void updateCustomMeasuredEnergyDataLocked(int customEnergyBucket,
             long totalEnergyUJ, @Nullable SparseLongArray uidEnergies) {
@@ -12532,7 +12270,7 @@
         if (mGlobalMeasuredEnergyStats == null) return;
         if (!mOnBatteryInternal || mIgnoreNextExternalStats || totalEnergyUJ <= 0) return;
 
-        mGlobalMeasuredEnergyStats.updateCustomBucket(customEnergyBucket, totalEnergyUJ, true);
+        mGlobalMeasuredEnergyStats.updateCustomBucket(customEnergyBucket, totalEnergyUJ);
 
         if (uidEnergies == null) return;
         final int numUids = uidEnergies.size();
@@ -12540,10 +12278,20 @@
             final int uidInt = mapUid(uidEnergies.keyAt(i));
             final long uidEnergyUJ = uidEnergies.valueAt(i);
             if (uidEnergyUJ == 0) continue;
-            // TODO(b/180030409): Worry about dead Uids (no longer in BSI) being revived by this,
-            //  or converse problem of not creating a new Uid if its first blame is recorded here.
-            final Uid uidObj = getUidStatsLocked(uidInt);
-            uidObj.addEnergyToCustomBucketLocked(uidEnergyUJ, customEnergyBucket, true);
+            final Uid uidObj = getAvailableUidStatsLocked(uidInt);
+            if (uidObj != null) {
+                uidObj.addEnergyToCustomBucketLocked(uidEnergyUJ, customEnergyBucket);
+            } else {
+                // Ignore any uid not already known to BatteryStats, rather than creating a new Uid.
+                // Otherwise we could end up reviving dead Uids. Note that the CPU data is updated
+                // first, so any uid that has used any CPU should already be known to BatteryStats.
+                // Recently removed uids (especially common for isolated uids) can reach this path
+                // and are ignored.
+                if (!Process.isIsolated(uidInt)) {
+                    Slog.w(TAG, "Received measured energy " + totalEnergyUJ + " for custom bucket "
+                        + customEnergyBucket + " for non-existent uid " + uidInt);
+                }
+            }
         }
     }
 
@@ -14626,7 +14374,7 @@
 
         Parcel p = Parcel.obtain();
         final long start = SystemClock.uptimeMillis();
-        writeHistoryBuffer(p, true, true);
+        writeHistoryBuffer(p, true);
         if (DEBUG) {
             Slog.d(TAG, "writeHistoryBuffer duration ms:"
                     + (SystemClock.uptimeMillis() - start) + " bytes:" + p.dataSize());
@@ -14720,7 +14468,7 @@
                 if (raw.length > 0) {
                     history.unmarshall(raw, 0, raw.length);
                     history.setDataPosition(0);
-                    readHistoryBuffer(history, true);
+                    readHistoryBuffer(history);
                 }
                 if (DEBUG) {
                     Slog.d(TAG, "readLocked history file::"
@@ -14744,10 +14492,6 @@
             mRecordingHistory = true;
             final long elapsedRealtimeMs = mClocks.elapsedRealtime();
             final long uptimeMs = mClocks.uptimeMillis();
-            if (USE_OLD_HISTORY) {
-                addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs,
-                        HistoryItem.CMD_START, mHistoryCur);
-            }
             addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_START, mHistoryCur);
             startRecordingHistory(elapsedRealtimeMs, uptimeMs, false);
         }
@@ -14759,7 +14503,7 @@
         return 0;
     }
 
-    void  readHistoryBuffer(Parcel in, boolean andOldHistory) throws ParcelFormatException {
+    void  readHistoryBuffer(Parcel in) throws ParcelFormatException {
         final int version = in.readInt();
         if (version != VERSION) {
             Slog.w("BatteryStats", "readHistoryBuffer: version got " + version
@@ -14787,10 +14531,6 @@
             in.setDataPosition(curPos + bufSize);
         }
 
-        if (andOldHistory) {
-            readOldHistory(in);
-        }
-
         if (DEBUG_HISTORY) {
             StringBuilder sb = new StringBuilder(128);
             sb.append("****************** OLD mHistoryBaseTimeMs: ");
@@ -14819,18 +14559,7 @@
         }
     }
 
-    void readOldHistory(Parcel in) {
-        if (!USE_OLD_HISTORY) {
-            return;
-        }
-        mHistory = mHistoryEnd = mHistoryCache = null;
-        while (in.dataAvail() > 0) {
-            HistoryItem rec = new HistoryItem(in);
-            addHistoryRecordLocked(rec);
-        }
-    }
-
-    void writeHistoryBuffer(Parcel out, boolean inclData, boolean andOldHistory) {
+    void writeHistoryBuffer(Parcel out, boolean inclData) {
         if (DEBUG_HISTORY) {
             StringBuilder sb = new StringBuilder(128);
             sb.append("****************** WRITING mHistoryBaseTimeMs: ");
@@ -14851,22 +14580,6 @@
         if (DEBUG_HISTORY) Slog.i(TAG, "***************** WRITING HISTORY: "
                 + mHistoryBuffer.dataSize() + " bytes at " + out.dataPosition());
         out.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize());
-
-        if (andOldHistory) {
-            writeOldHistory(out);
-        }
-    }
-
-    void writeOldHistory(Parcel out) {
-        if (!USE_OLD_HISTORY) {
-            return;
-        }
-        HistoryItem rec = mHistory;
-        while (rec != null) {
-            if (rec.time >= 0) rec.writeToParcel(out, 0);
-            rec = rec.next;
-        }
-        out.writeLong(-1);
     }
 
     public void readSummaryFromParcel(Parcel in) throws ParcelFormatException {
@@ -14879,7 +14592,7 @@
 
         boolean inclHistory = in.readBoolean();
         if (inclHistory) {
-            readHistoryBuffer(in, true);
+            readHistoryBuffer(in);
             mBatteryStatsHistory.readFromParcel(in);
         }
 
@@ -15398,7 +15111,7 @@
 
         out.writeBoolean(inclHistory);
         if (inclHistory) {
-            writeHistoryBuffer(out, true, true);
+            writeHistoryBuffer(out, true);
             mBatteryStatsHistory.writeToParcel(out);
         }
 
@@ -15911,7 +15624,7 @@
             throw new ParcelFormatException("Bad magic number: #" + Integer.toHexString(magic));
         }
 
-        readHistoryBuffer(in, false);
+        readHistoryBuffer(in);
         mBatteryStatsHistory.readFromParcel(in);
 
         mStartCount = in.readInt();
@@ -16150,7 +15863,7 @@
 
         out.writeInt(MAGIC);
 
-        writeHistoryBuffer(out, true, false);
+        writeHistoryBuffer(out, true);
         mBatteryStatsHistory.writeToParcel(out);
 
         out.writeInt(mStartCount);
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index eef9fa7..15b584d 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -22,12 +22,15 @@
 import android.os.BatteryUsageStats;
 import android.os.BatteryUsageStatsQuery;
 import android.os.Bundle;
-import android.os.SystemClock;
+import android.os.UidBatteryConsumer;
 import android.os.UserHandle;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Uses accumulated battery stats data and PowerCalculators to produce power
@@ -85,7 +88,7 @@
     }
 
     /**
-     * Returns a snapshot of battery attribution data.
+     * Returns snapshots of battery attribution data, one per supplied query.
      */
     public List<BatteryUsageStats> getBatteryUsageStats(List<BatteryUsageStatsQuery> queries) {
 
@@ -112,12 +115,19 @@
         return results;
     }
 
-    private BatteryUsageStats getBatteryUsageStats(BatteryUsageStatsQuery query) {
+    /**
+     * Returns a snapshot of battery attribution data.
+     */
+    @VisibleForTesting
+    public BatteryUsageStats getBatteryUsageStats(BatteryUsageStatsQuery query) {
+        final long realtimeUs = mStats.mClocks.elapsedRealtime() * 1000;
+        final long uptimeUs = mStats.mClocks.uptimeMillis() * 1000;
+
         final long[] customMeasuredEnergiesMicroJoules =
                 mStats.getCustomMeasuredEnergiesMicroJoules();
         final int customPowerComponentCount = customMeasuredEnergiesMicroJoules != null
-                        ? customMeasuredEnergiesMicroJoules.length
-                        : 0;
+                ? customMeasuredEnergiesMicroJoules.length
+                : 0;
 
         // TODO(b/174186358): read extra time component number from configuration
         final int customTimeComponentCount = 0;
@@ -128,12 +138,14 @@
 
         SparseArray<? extends BatteryStats.Uid> uidStats = mStats.getUidStats();
         for (int i = uidStats.size() - 1; i >= 0; i--) {
-            batteryUsageStatsBuilder.getOrCreateUidBatteryConsumerBuilder(uidStats.valueAt(i));
+            final BatteryStats.Uid uid = uidStats.valueAt(i);
+            batteryUsageStatsBuilder.getOrCreateUidBatteryConsumerBuilder(uid)
+                    .setTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND,
+                            getProcessBackgroundTimeMs(uid, realtimeUs))
+                    .setTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND,
+                            getProcessForegroundTimeMs(uid, realtimeUs));
         }
 
-        final long realtimeUs = SystemClock.elapsedRealtime() * 1000;
-        final long uptimeUs = SystemClock.uptimeMillis() * 1000;
-
         final List<PowerCalculator> powerCalculators = getPowerCalculators();
         for (int i = 0, count = powerCalculators.size(); i < count; i++) {
             PowerCalculator powerCalculator = powerCalculators.get(i);
@@ -141,6 +153,51 @@
                     query);
         }
 
+        if ((query.getFlags()
+                & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY) != 0) {
+            ArrayList<BatteryStats.HistoryTag> tags = new ArrayList<>(
+                    mStats.mHistoryTagPool.size());
+            for (Map.Entry<BatteryStats.HistoryTag, Integer> entry :
+                    mStats.mHistoryTagPool.entrySet()) {
+                final BatteryStats.HistoryTag tag = entry.getKey();
+                tag.poolIdx = entry.getValue();
+                tags.add(tag);
+            }
+
+            batteryUsageStatsBuilder.setBatteryHistory(mStats.mHistoryBuffer, tags);
+        }
+
         return batteryUsageStatsBuilder.build();
     }
+
+    private long getProcessForegroundTimeMs(BatteryStats.Uid uid, long realtimeUs) {
+        final long topStateDurationMs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_TOP,
+                realtimeUs, BatteryStats.STATS_SINCE_CHARGED) / 1000;
+
+        long foregroundActivityDurationMs = 0;
+        final BatteryStats.Timer foregroundActivityTimer = uid.getForegroundActivityTimer();
+        if (foregroundActivityTimer != null) {
+            foregroundActivityDurationMs = foregroundActivityTimer.getTotalTimeLocked(realtimeUs,
+                    BatteryStats.STATS_SINCE_CHARGED) / 1000;
+        }
+
+        // Use the min value of STATE_TOP time and foreground activity time, since both of these
+        // times are imprecise
+        final long foregroundDurationMs = Math.min(topStateDurationMs,
+                foregroundActivityDurationMs);
+
+        long foregroundServiceDurationMs = 0;
+        final BatteryStats.Timer foregroundServiceTimer = uid.getForegroundServiceTimer();
+        if (foregroundServiceTimer != null) {
+            foregroundServiceDurationMs = foregroundServiceTimer.getTotalTimeLocked(realtimeUs,
+                    BatteryStats.STATS_SINCE_CHARGED) / 1000;
+        }
+
+        return foregroundDurationMs + foregroundServiceDurationMs;
+    }
+
+    private long getProcessBackgroundTimeMs(BatteryStats.Uid uid, long realtimeUs) {
+        return uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_BACKGROUND, realtimeUs,
+                BatteryStats.STATS_SINCE_CHARGED) / 1000;
+    }
 }
diff --git a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
index 4299f09..64c68ce 100644
--- a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
+++ b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
@@ -152,6 +152,10 @@
      */
     public void removeUid(int uid) {
         mLastTimes.delete(uid);
+
+        if (mBpfTimesAvailable) {
+            mBpfReader.removeUidsInRange(uid, uid);
+        }
     }
 
     /**
diff --git a/core/java/com/android/internal/os/TEST_MAPPING b/core/java/com/android/internal/os/TEST_MAPPING
index 9698f19..791e9ad 100644
--- a/core/java/com/android/internal/os/TEST_MAPPING
+++ b/core/java/com/android/internal/os/TEST_MAPPING
@@ -1,6 +1,23 @@
 {
   "presubmit": [
     {
+      "file_patterns": ["Battery[^/]*\\.java"],
+      "name": "FrameworksCoreTests",
+      "options": [
+        { "include-filter": "com.android.internal.os.BatteryStatsTests" },
+        { "exclude-annotation": "com.android.internal.os.SkipPresubmit" }
+      ]
+    },
+    {
+      "file_patterns": ["Battery[^/]*\\.java"],
+      "name": "FrameworksServicesTests",
+      "options": [
+        { "include-filter": "com.android.server.am.BatteryStatsServiceTest" },
+        { "include-filter": "com.android.server.am.MeasuredEnergySnapshotTest" },
+        { "include-filter": "com.android.server.am.BatteryExternalStatsWorkerTest" }
+      ]
+    },
+    {
       "name": "FrameworksCoreTests",
       "options": [
         {
diff --git a/core/java/com/android/internal/os/UsageBasedPowerEstimator.java b/core/java/com/android/internal/os/UsageBasedPowerEstimator.java
index 5910b61..fd52014 100644
--- a/core/java/com/android/internal/os/UsageBasedPowerEstimator.java
+++ b/core/java/com/android/internal/os/UsageBasedPowerEstimator.java
@@ -32,6 +32,10 @@
         mAveragePowerMahPerMs = averagePowerMilliAmp / MILLIS_IN_HOUR;
     }
 
+    public boolean isSupported() {
+        return mAveragePowerMahPerMs != 0;
+    }
+
     /**
      * Given a {@link BatteryStats.Timer}, returns the accumulated duration.
      */
diff --git a/core/java/com/android/internal/os/WifiPowerCalculator.java b/core/java/com/android/internal/os/WifiPowerCalculator.java
index 63763f7..98f613f 100644
--- a/core/java/com/android/internal/os/WifiPowerCalculator.java
+++ b/core/java/com/android/internal/os/WifiPowerCalculator.java
@@ -15,8 +15,13 @@
  */
 package com.android.internal.os;
 
+import android.os.BatteryConsumer;
 import android.os.BatteryStats;
+import android.os.BatteryUsageStats;
+import android.os.BatteryUsageStatsQuery;
 import android.os.Process;
+import android.os.SystemBatteryConsumer;
+import android.os.UidBatteryConsumer;
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.SparseArray;
@@ -30,25 +35,93 @@
 public class WifiPowerCalculator extends PowerCalculator {
     private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
     private static final String TAG = "WifiPowerCalculator";
-    private final double mIdleCurrentMa;
-    private final double mTxCurrentMa;
-    private final double mRxCurrentMa;
-    private final PowerProfile mPowerProfile;
+    private final UsageBasedPowerEstimator mIdlePowerEstimator;
+    private final UsageBasedPowerEstimator mTxPowerEstimator;
+    private final UsageBasedPowerEstimator mRxPowerEstimator;
+    private final UsageBasedPowerEstimator mPowerOnPowerEstimator;
+    private final UsageBasedPowerEstimator mScanPowerEstimator;
+    private final UsageBasedPowerEstimator mBatchScanPowerEstimator;
     private final boolean mHasWifiPowerController;
-    private double mTotalAppPowerDrain = 0;
-    private long mTotalAppRunningTime = 0;
-    private WifiPowerEstimator mWifiPowerEstimator;
-    private boolean mHasWifiPowerReporting;
+    private final double mWifiPowerPerPacket;
+
+    private static class PowerDurationAndTraffic {
+        public double powerMah;
+        public long durationMs;
+
+        public long wifiRxPackets;
+        public long wifiTxPackets;
+        public long wifiRxBytes;
+        public long wifiTxBytes;
+    }
 
     public WifiPowerCalculator(PowerProfile profile) {
-        mPowerProfile = profile;
+        mPowerOnPowerEstimator = new UsageBasedPowerEstimator(
+                profile.getAveragePower(PowerProfile.POWER_WIFI_ON));
+        mScanPowerEstimator = new UsageBasedPowerEstimator(
+                profile.getAveragePower(PowerProfile.POWER_WIFI_SCAN));
+        mBatchScanPowerEstimator = new UsageBasedPowerEstimator(
+                profile.getAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN));
+        mIdlePowerEstimator = new UsageBasedPowerEstimator(
+                profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_IDLE));
+        mTxPowerEstimator = new UsageBasedPowerEstimator(
+                profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_TX));
+        mRxPowerEstimator = new UsageBasedPowerEstimator(
+                profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_RX));
 
-        mIdleCurrentMa = profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_IDLE);
-        mTxCurrentMa = profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_TX);
-        mRxCurrentMa = profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_RX);
+        mWifiPowerPerPacket = getWifiPowerPerPacket(profile);
 
-        mHasWifiPowerController = mIdleCurrentMa != 0 && mTxCurrentMa != 0 && mRxCurrentMa != 0;
-        mWifiPowerEstimator = new WifiPowerEstimator(mPowerProfile);
+        mHasWifiPowerController =
+                mIdlePowerEstimator.isSupported() && mTxPowerEstimator.isSupported()
+                        && mRxPowerEstimator.isSupported();
+    }
+
+    @Override
+    public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
+            long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
+
+        // batteryStats.hasWifiActivityReporting can change if we get energy data at a later point,
+        // so always check this field.
+        final boolean hasWifiPowerReporting =
+                mHasWifiPowerController && batteryStats.hasWifiActivityReporting();
+
+        final SystemBatteryConsumer.Builder systemBatteryConsumerBuilder =
+                builder.getOrCreateSystemBatteryConsumerBuilder(
+                        SystemBatteryConsumer.DRAIN_TYPE_WIFI);
+
+        long totalAppDurationMs = 0;
+        double totalAppPowerMah = 0;
+        final PowerDurationAndTraffic powerDurationAndTraffic = new PowerDurationAndTraffic();
+        final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
+                builder.getUidBatteryConsumerBuilders();
+        for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
+            final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
+            calculateApp(powerDurationAndTraffic, app.getBatteryStatsUid(), rawRealtimeUs,
+                    BatteryStats.STATS_SINCE_CHARGED,
+                    hasWifiPowerReporting);
+
+            totalAppDurationMs += powerDurationAndTraffic.durationMs;
+            totalAppPowerMah += powerDurationAndTraffic.powerMah;
+
+            app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI,
+                    powerDurationAndTraffic.durationMs);
+            app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI,
+                    powerDurationAndTraffic.powerMah);
+
+            if (app.getUid() == Process.WIFI_UID) {
+                systemBatteryConsumerBuilder.addUidBatteryConsumer(app);
+                app.excludeFromBatteryUsageStats();
+            }
+        }
+
+        calculateRemaining(powerDurationAndTraffic, batteryStats, rawRealtimeUs,
+                BatteryStats.STATS_SINCE_CHARGED,
+                hasWifiPowerReporting, totalAppDurationMs, totalAppPowerMah);
+
+        systemBatteryConsumerBuilder
+                .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI,
+                        powerDurationAndTraffic.durationMs)
+                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI,
+                        powerDurationAndTraffic.powerMah);
     }
 
     /**
@@ -64,100 +137,151 @@
 
         // batteryStats.hasWifiActivityReporting can change if we get energy data at a later point,
         // so always check this field.
-        mHasWifiPowerReporting = mHasWifiPowerController && batteryStats.hasWifiActivityReporting();
+        final boolean hasWifiPowerReporting =
+                mHasWifiPowerController && batteryStats.hasWifiActivityReporting();
 
-        super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers);
+        final BatterySipper bs = new BatterySipper(BatterySipper.DrainType.WIFI, null, 0);
 
-        BatterySipper bs = new BatterySipper(BatterySipper.DrainType.WIFI, null, 0);
-        calculateRemaining(bs, batteryStats, rawRealtimeUs, rawUptimeUs, statsType);
-
+        long totalAppDurationMs = 0;
+        double totalAppPowerMah = 0;
+        final PowerDurationAndTraffic powerDurationAndTraffic = new PowerDurationAndTraffic();
         for (int i = sippers.size() - 1; i >= 0; i--) {
-            BatterySipper app = sippers.get(i);
-            if (app.getUid() == Process.WIFI_UID) {
-                if (DEBUG) Log.d(TAG, "WiFi adding sipper " + app + ": cpu=" + app.cpuTimeMs);
-                app.isAggregated = true;
-                bs.add(app);
+            final BatterySipper app = sippers.get(i);
+            if (app.drainType == BatterySipper.DrainType.APP) {
+                calculateApp(powerDurationAndTraffic, app.uidObj, rawRealtimeUs, statsType,
+                        hasWifiPowerReporting);
+
+                totalAppDurationMs += powerDurationAndTraffic.durationMs;
+                totalAppPowerMah += powerDurationAndTraffic.powerMah;
+
+                app.wifiPowerMah = powerDurationAndTraffic.powerMah;
+                app.wifiRunningTimeMs = powerDurationAndTraffic.durationMs;
+                app.wifiRxBytes = powerDurationAndTraffic.wifiRxBytes;
+                app.wifiRxPackets = powerDurationAndTraffic.wifiRxPackets;
+                app.wifiTxBytes = powerDurationAndTraffic.wifiTxBytes;
+                app.wifiTxPackets = powerDurationAndTraffic.wifiTxPackets;
+                if (app.getUid() == Process.WIFI_UID) {
+                    if (DEBUG) Log.d(TAG, "WiFi adding sipper " + app + ": cpu=" + app.cpuTimeMs);
+                    app.isAggregated = true;
+                    bs.add(app);
+                }
             }
         }
+
+        calculateRemaining(powerDurationAndTraffic, batteryStats, rawRealtimeUs, statsType,
+                hasWifiPowerReporting, totalAppDurationMs, totalAppPowerMah);
+
+        bs.wifiRunningTimeMs += powerDurationAndTraffic.durationMs;
+        bs.wifiPowerMah += powerDurationAndTraffic.powerMah;
+
         if (bs.sumPower() > 0) {
             sippers.add(bs);
         }
     }
 
-    @Override
-    protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
-            long rawUptimeUs, int statsType) {
-        if (!mHasWifiPowerReporting) {
-            mWifiPowerEstimator.calculateApp(app, u, rawRealtimeUs, rawUptimeUs, statsType);
-            return;
-        }
-
-        final BatteryStats.ControllerActivityCounter counter = u.getWifiControllerActivity();
-        if (counter == null) {
-            return;
-        }
-
-        final long idleTime = counter.getIdleTimeCounter().getCountLocked(statsType);
-        final long txTime = counter.getTxTimeCounters()[0].getCountLocked(statsType);
-        final long rxTime = counter.getRxTimeCounter().getCountLocked(statsType);
-        app.wifiRunningTimeMs = idleTime + rxTime + txTime;
-        mTotalAppRunningTime += app.wifiRunningTimeMs;
-
-        app.wifiPowerMah =
-                ((idleTime * mIdleCurrentMa) + (txTime * mTxCurrentMa) + (rxTime * mRxCurrentMa))
-                        / (1000 * 60 * 60);
-        mTotalAppPowerDrain += app.wifiPowerMah;
-
-        app.wifiRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_RX_DATA,
+    private void calculateApp(PowerDurationAndTraffic powerDurationAndTraffic, BatteryStats.Uid u,
+            long rawRealtimeUs,
+            int statsType, boolean hasWifiPowerReporting) {
+        powerDurationAndTraffic.wifiRxPackets = u.getNetworkActivityPackets(
+                BatteryStats.NETWORK_WIFI_RX_DATA,
                 statsType);
-        app.wifiTxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_TX_DATA,
+        powerDurationAndTraffic.wifiTxPackets = u.getNetworkActivityPackets(
+                BatteryStats.NETWORK_WIFI_TX_DATA,
                 statsType);
-        app.wifiRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_RX_DATA,
+        powerDurationAndTraffic.wifiRxBytes = u.getNetworkActivityBytes(
+                BatteryStats.NETWORK_WIFI_RX_DATA,
                 statsType);
-        app.wifiTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_TX_DATA,
+        powerDurationAndTraffic.wifiTxBytes = u.getNetworkActivityBytes(
+                BatteryStats.NETWORK_WIFI_TX_DATA,
                 statsType);
 
-        if (DEBUG && app.wifiPowerMah != 0) {
-            Log.d(TAG, "UID " + u.getUid() + ": idle=" + idleTime + "ms rx=" + rxTime + "ms tx=" +
-                    txTime + "ms power=" + formatCharge(app.wifiPowerMah));
+        if (hasWifiPowerReporting) {
+            final BatteryStats.ControllerActivityCounter counter = u.getWifiControllerActivity();
+            if (counter != null) {
+                final long idleTime = counter.getIdleTimeCounter().getCountLocked(statsType);
+                final long txTime = counter.getTxTimeCounters()[0].getCountLocked(statsType);
+                final long rxTime = counter.getRxTimeCounter().getCountLocked(statsType);
+
+                powerDurationAndTraffic.durationMs = idleTime + rxTime + txTime;
+                powerDurationAndTraffic.powerMah = mIdlePowerEstimator.calculatePower(idleTime)
+                        + mTxPowerEstimator.calculatePower(txTime)
+                        + mRxPowerEstimator.calculatePower(rxTime);
+
+                if (DEBUG && powerDurationAndTraffic.powerMah != 0) {
+                    Log.d(TAG, "UID " + u.getUid() + ": idle=" + idleTime + "ms rx=" + rxTime
+                            + "ms tx=" + txTime + "ms power=" + formatCharge(
+                            powerDurationAndTraffic.powerMah));
+                }
+            }
+        } else {
+            final double wifiPacketPower = (
+                    powerDurationAndTraffic.wifiRxPackets + powerDurationAndTraffic.wifiTxPackets)
+                    * mWifiPowerPerPacket;
+            final long wifiRunningTime = u.getWifiRunningTime(rawRealtimeUs, statsType) / 1000;
+            final long wifiScanTimeMs = u.getWifiScanTime(rawRealtimeUs, statsType) / 1000;
+            long batchScanTimeMs = 0;
+            for (int bin = 0; bin < BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS; bin++) {
+                batchScanTimeMs += u.getWifiBatchedScanTime(bin, rawRealtimeUs, statsType) / 1000;
+            }
+
+            powerDurationAndTraffic.durationMs = wifiRunningTime;
+            powerDurationAndTraffic.powerMah = wifiPacketPower
+                    + mPowerOnPowerEstimator.calculatePower(wifiRunningTime)
+                    + mScanPowerEstimator.calculatePower(wifiScanTimeMs)
+                    + mBatchScanPowerEstimator.calculatePower(batchScanTimeMs);
+
+            if (DEBUG && powerDurationAndTraffic.powerMah != 0) {
+                Log.d(TAG, "UID " + u.getUid() + ": power=" + formatCharge(
+                        powerDurationAndTraffic.powerMah));
+            }
         }
     }
 
-    private void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
-            long rawUptimeUs, int statsType) {
-        if (!mHasWifiPowerReporting) {
-            mWifiPowerEstimator.calculateRemaining(app, stats, rawRealtimeUs, rawUptimeUs,
-                    statsType);
-            return;
+    private void calculateRemaining(PowerDurationAndTraffic powerDurationAndTraffic,
+            BatteryStats stats, long rawRealtimeUs,
+            int statsType, boolean hasWifiPowerReporting, long totalAppDurationMs,
+            double totalAppPowerMah) {
+        long totalDurationMs;
+        double totalPowerMah;
+        if (hasWifiPowerReporting) {
+            final BatteryStats.ControllerActivityCounter counter =
+                    stats.getWifiControllerActivity();
+
+            final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(statsType);
+            final long txTimeMs = counter.getTxTimeCounters()[0].getCountLocked(statsType);
+            final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(statsType);
+
+            totalDurationMs = idleTimeMs + rxTimeMs + txTimeMs;
+
+            totalPowerMah =
+                    counter.getPowerCounter().getCountLocked(statsType) / (double) (1000 * 60 * 60);
+            if (totalPowerMah == 0) {
+                // Some controllers do not report power drain, so we can calculate it here.
+                totalPowerMah = mIdlePowerEstimator.calculatePower(idleTimeMs)
+                        + mTxPowerEstimator.calculatePower(txTimeMs)
+                        + mRxPowerEstimator.calculatePower(rxTimeMs);
+            }
+        } else {
+            totalDurationMs = stats.getGlobalWifiRunningTime(rawRealtimeUs, statsType) / 1000;
+            totalPowerMah = mPowerOnPowerEstimator.calculatePower(totalDurationMs);
         }
 
-        final BatteryStats.ControllerActivityCounter counter = stats.getWifiControllerActivity();
-
-        final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(statsType);
-        final long txTimeMs = counter.getTxTimeCounters()[0].getCountLocked(statsType);
-        final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(statsType);
-
-        app.wifiRunningTimeMs = Math.max(0,
-                (idleTimeMs + rxTimeMs + txTimeMs) - mTotalAppRunningTime);
-
-        double powerDrainMah = counter.getPowerCounter().getCountLocked(statsType)
-                / (double) (1000 * 60 * 60);
-        if (powerDrainMah == 0) {
-            // Some controllers do not report power drain, so we can calculate it here.
-            powerDrainMah = ((idleTimeMs * mIdleCurrentMa) + (txTimeMs * mTxCurrentMa)
-                    + (rxTimeMs * mRxCurrentMa)) / (1000 * 60 * 60);
-        }
-        app.wifiPowerMah = Math.max(0, powerDrainMah - mTotalAppPowerDrain);
+        powerDurationAndTraffic.durationMs = Math.max(0, totalDurationMs - totalAppDurationMs);
+        powerDurationAndTraffic.powerMah = Math.max(0, totalPowerMah - totalAppPowerMah);
 
         if (DEBUG) {
-            Log.d(TAG, "left over WiFi power: " + formatCharge(app.wifiPowerMah));
+            Log.d(TAG, "left over WiFi power: " + formatCharge(powerDurationAndTraffic.powerMah));
         }
     }
 
-    @Override
-    public void reset() {
-        mTotalAppPowerDrain = 0;
-        mTotalAppRunningTime = 0;
-        mWifiPowerEstimator.reset();
+    /**
+     * Return estimated power per Wi-Fi packet in mAh/packet where 1 packet = 2 KB.
+     */
+    private static double getWifiPowerPerPacket(PowerProfile profile) {
+        // TODO(b/179392913): Extract average bit rates from system
+        final long wifiBps = 1000000;
+        final double averageWifiActivePower =
+                profile.getAveragePower(PowerProfile.POWER_WIFI_ACTIVE) / 3600;
+        return averageWifiActivePower / (((double) wifiBps) / 8 / 2048);
     }
 }
diff --git a/core/java/com/android/internal/os/WifiPowerEstimator.java b/core/java/com/android/internal/os/WifiPowerEstimator.java
deleted file mode 100644
index d0a105c..0000000
--- a/core/java/com/android/internal/os/WifiPowerEstimator.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.os;
-
-import android.os.BatteryStats;
-import android.os.Process;
-import android.os.UserHandle;
-import android.util.Log;
-import android.util.SparseArray;
-
-import java.util.List;
-
-/**
- * Estimates WiFi power usage based on timers in BatteryStats.
- */
-public class WifiPowerEstimator extends PowerCalculator {
-    private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
-    private static final String TAG = "WifiPowerEstimator";
-    private final double mWifiPowerPerPacket;
-    private final double mWifiPowerOn;
-    private final double mWifiPowerScan;
-    private final double mWifiPowerBatchScan;
-    private long mTotalAppWifiRunningTimeMs = 0;
-
-    public WifiPowerEstimator(PowerProfile profile) {
-        mWifiPowerPerPacket = getWifiPowerPerPacket(profile);
-        mWifiPowerOn = profile.getAveragePower(PowerProfile.POWER_WIFI_ON);
-        mWifiPowerScan = profile.getAveragePower(PowerProfile.POWER_WIFI_SCAN);
-        mWifiPowerBatchScan = profile.getAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN);
-    }
-
-    @Override
-    public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
-            long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
-        super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers);
-
-        BatterySipper bs = new BatterySipper(BatterySipper.DrainType.WIFI, null, 0);
-        calculateRemaining(bs, batteryStats, rawRealtimeUs, rawUptimeUs, statsType);
-
-        for (int i = sippers.size() - 1; i >= 0; i--) {
-            BatterySipper app = sippers.get(i);
-            if (app.getUid() == Process.WIFI_UID) {
-                if (DEBUG) Log.d(TAG, "WiFi adding sipper " + app + ": cpu=" + app.cpuTimeMs);
-                app.isAggregated = true;
-                bs.add(app);
-            }
-        }
-        if (bs.sumPower() > 0) {
-            sippers.add(bs);
-        }
-    }
-
-    /**
-     * Return estimated power per Wi-Fi packet in mAh/packet where 1 packet = 2 KB.
-     */
-    private static double getWifiPowerPerPacket(PowerProfile profile) {
-        final long WIFI_BPS = 1000000; // TODO: Extract average bit rates from system
-        final double WIFI_POWER = profile.getAveragePower(PowerProfile.POWER_WIFI_ACTIVE)
-                / 3600;
-        return WIFI_POWER / (((double)WIFI_BPS) / 8 / 2048);
-    }
-
-    @Override
-    protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
-                             long rawUptimeUs, int statsType) {
-        app.wifiRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_RX_DATA,
-                statsType);
-        app.wifiTxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_TX_DATA,
-                statsType);
-        app.wifiRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_RX_DATA,
-                statsType);
-        app.wifiTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_TX_DATA,
-                statsType);
-
-        final double wifiPacketPower = (app.wifiRxPackets + app.wifiTxPackets)
-                * mWifiPowerPerPacket;
-
-        app.wifiRunningTimeMs = u.getWifiRunningTime(rawRealtimeUs, statsType) / 1000;
-        mTotalAppWifiRunningTimeMs += app.wifiRunningTimeMs;
-        final double wifiLockPower = (app.wifiRunningTimeMs * mWifiPowerOn) / (1000*60*60);
-
-        final long wifiScanTimeMs = u.getWifiScanTime(rawRealtimeUs, statsType) / 1000;
-        final double wifiScanPower = (wifiScanTimeMs * mWifiPowerScan) / (1000*60*60);
-
-        double wifiBatchScanPower = 0;
-        for (int bin = 0; bin < BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS; bin++) {
-            final long batchScanTimeMs =
-                    u.getWifiBatchedScanTime(bin, rawRealtimeUs, statsType) / 1000;
-            final double batchScanPower = (batchScanTimeMs * mWifiPowerBatchScan) / (1000*60*60);
-            wifiBatchScanPower += batchScanPower;
-        }
-
-        app.wifiPowerMah = wifiPacketPower + wifiLockPower + wifiScanPower + wifiBatchScanPower;
-        if (DEBUG && app.wifiPowerMah != 0) {
-            Log.d(TAG, "UID " + u.getUid() + ": power=" + formatCharge(app.wifiPowerMah));
-        }
-    }
-
-    void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
-                                   long rawUptimeUs, int statsType) {
-        final long totalRunningTimeMs = stats.getGlobalWifiRunningTime(rawRealtimeUs, statsType)
-                / 1000;
-        final double powerDrain = ((totalRunningTimeMs - mTotalAppWifiRunningTimeMs) * mWifiPowerOn)
-                / (1000*60*60);
-        app.wifiRunningTimeMs = totalRunningTimeMs;
-        app.wifiPowerMah = Math.max(0, powerDrain);
-    }
-
-    @Override
-    public void reset() {
-        mTotalAppWifiRunningTimeMs = 0;
-    }
-}
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index b99c953..6b1d408 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -18,8 +18,8 @@
 
 import static android.system.OsConstants.O_CLOEXEC;
 
-import static com.android.internal.os.ZygoteConnectionConstants.MAX_ZYGOTE_ARGC;
-
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.pm.ApplicationInfo;
 import android.net.Credentials;
 import android.net.LocalServerSocket;
@@ -36,17 +36,16 @@
 
 import com.android.internal.net.NetworkUtilsInternal;
 
+import dalvik.annotation.optimization.CriticalNative;
 import dalvik.annotation.optimization.FastNative;
 import dalvik.system.ZygoteHooks;
 
 import libcore.io.IoUtils;
 
-import java.io.BufferedReader;
 import java.io.ByteArrayOutputStream;
 import java.io.DataOutputStream;
 import java.io.FileDescriptor;
 import java.io.IOException;
-import java.io.InputStreamReader;
 
 /** @hide */
 public final class Zygote {
@@ -238,6 +237,8 @@
      */
     public static final String CHILD_ZYGOTE_UID_RANGE_END = "--uid-range-end=";
 
+    private static final String TAG = "Zygote";
+
     /** Prefix prepended to socket names created by init */
     private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
 
@@ -408,6 +409,10 @@
         // Note that this event ends at the end of handleChildProc.
         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
 
+        if (gids != null && gids.length > 0) {
+            NetworkUtilsInternal.setAllowNetworkingForProcess(containsInetGid(gids));
+        }
+
         // Set the Java Language thread priority to the default value for new apps.
         Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
 
@@ -580,114 +585,163 @@
     private static native int nativeGetUsapPoolEventFD();
 
     /**
-     * Fork a new unspecialized app process from the zygote
+     * Fork a new unspecialized app process from the zygote. Adds the Usap to the native
+     * Usap table.
      *
      * @param usapPoolSocket  The server socket the USAP will call accept on
-     * @param sessionSocketRawFDs  Anonymous session sockets that are currently open
-     * @param isPriorityFork  Value controlling the process priority level until accept is called
-     * @return In the Zygote process this function will always return null; in unspecialized app
-     *         processes this function will return a Runnable object representing the new
-     *         application that is passed up from usapMain.
+     * @param sessionSocketRawFDs  Anonymous session sockets that are currently open.
+     *         These are closed in the child.
+     * @param isPriorityFork Raise the initial process priority level because this is on the
+     *         critical path for application startup.
+     * @return In the child process, this returns a Runnable that waits for specialization
+     *         info to start an app process. In the sygote/parent process this returns null.
      */
-    static Runnable forkUsap(LocalServerSocket usapPoolSocket,
-                             int[] sessionSocketRawFDs,
-                             boolean isPriorityFork) {
-        FileDescriptor[] pipeFDs;
+    static @Nullable Runnable forkUsap(LocalServerSocket usapPoolSocket,
+                                       int[] sessionSocketRawFDs,
+                                       boolean isPriorityFork) {
+        FileDescriptor readFD;
+        FileDescriptor writeFD;
 
         try {
-            pipeFDs = Os.pipe2(O_CLOEXEC);
+            FileDescriptor[] pipeFDs = Os.pipe2(O_CLOEXEC);
+            readFD = pipeFDs[0];
+            writeFD = pipeFDs[1];
         } catch (ErrnoException errnoEx) {
             throw new IllegalStateException("Unable to create USAP pipe.", errnoEx);
         }
 
-        int pid =
-                nativeForkUsap(pipeFDs[0].getInt$(), pipeFDs[1].getInt$(),
-                               sessionSocketRawFDs, isPriorityFork);
-
+        int pid = nativeForkApp(readFD.getInt$(), writeFD.getInt$(),
+                                sessionSocketRawFDs, /*argsKnown=*/ false, isPriorityFork);
         if (pid == 0) {
-            IoUtils.closeQuietly(pipeFDs[0]);
-            return usapMain(usapPoolSocket, pipeFDs[1]);
+            IoUtils.closeQuietly(readFD);
+            return childMain(null, usapPoolSocket, writeFD);
+        } else if (pid == -1) {
+            // Fork failed.
+            return null;
         } else {
-            // The read-end of the pipe will be closed by the native code.
-            // See removeUsapTableEntry();
-            IoUtils.closeQuietly(pipeFDs[1]);
+            // readFD will be closed by the native code. See removeUsapTableEntry();
+            IoUtils.closeQuietly(writeFD);
+            nativeAddUsapTableEntry(pid, readFD.getInt$());
             return null;
         }
     }
 
-    private static native int nativeForkUsap(int readPipeFD,
-                                             int writePipeFD,
-                                             int[] sessionSocketRawFDs,
-                                             boolean isPriorityFork);
+    private static native int nativeForkApp(int readPipeFD,
+                                            int writePipeFD,
+                                            int[] sessionSocketRawFDs,
+                                            boolean argsKnown,
+                                            boolean isPriorityFork);
 
     /**
-     * This function is used by unspecialized app processes to wait for specialization requests from
-     * the system server.
+     * Add an entry for a new Usap to the table maintained in native code.
+     */
+    @CriticalNative
+    private static native void nativeAddUsapTableEntry(int pid, int readPipeFD);
+
+    /**
+     * Fork a new app process from the zygote. argBuffer contains a fork command that
+     * request neither a child zygote, nor a wrapped process. Continue to accept connections
+     * on the specified socket, use those to refill argBuffer, and continue to process
+     * sufficiently simple fork requests. We presume that the only open file descriptors
+     * requiring special treatment are the session socket embedded in argBuffer, and
+     * zygoteSocket.
+     * @param argBuffer containing initial command and the connected socket from which to
+     *         read more
+     * @param zygoteSocket socket from which to obtain new connections when current argBuffer
+     *         one is disconnected
+     * @param expectedUId Uid of peer for initial requests. Subsequent requests from a different
+     *               peer will cause us to return rather than perform the requested fork.
+     * @param minUid Minimum Uid enforced for all but first fork request. The caller checks
+     *               the Uid policy for the initial request.
+     * @param firstNiceName name of first created process. Used for error reporting only.
+     * @return A Runnable in each child process, null in the parent.
+     * If this returns in then argBuffer still contains a command needing to be executed.
+     */
+    static @Nullable Runnable forkSimpleApps(@NonNull ZygoteCommandBuffer argBuffer,
+                                             @NonNull FileDescriptor zygoteSocket,
+                                             int expectedUid,
+                                             int minUid,
+                                             @Nullable String firstNiceName) {
+        boolean in_child =
+                argBuffer.forkRepeatedly(zygoteSocket, expectedUid, minUid, firstNiceName);
+        if (in_child) {
+            return childMain(argBuffer, /*usapPoolSocket=*/null, /*writePipe=*/null);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Specialize the current process into one described by argBuffer or the command read from
+     * usapPoolSocket. Exactly one of those must be null. If we are given an argBuffer, we close
+     * it. Used both for a specializing a USAP process, and for process creation without USAPs.
+     * In both cases, we specialize the process after first returning to Java code.
      *
      * @param writePipe  The write end of the reporting pipe used to communicate with the poll loop
      *                   of the ZygoteServer.
      * @return A runnable oject representing the new application.
      */
-    private static Runnable usapMain(LocalServerSocket usapPoolSocket,
-                                     FileDescriptor writePipe) {
+    private static Runnable childMain(@Nullable ZygoteCommandBuffer argBuffer,
+                                      @Nullable LocalServerSocket usapPoolSocket,
+                                      FileDescriptor writePipe) {
         final int pid = Process.myPid();
-        Process.setArgV0(Process.is64Bit() ? "usap64" : "usap32");
 
-        LocalSocket sessionSocket = null;
         DataOutputStream usapOutputStream = null;
-        Credentials peerCredentials = null;
         ZygoteArguments args = null;
 
-        // Change the priority to max before calling accept so we can respond to new specialization
-        // requests as quickly as possible.  This will be reverted to the default priority in the
-        // native specialization code.
-        boostUsapPriority();
+        // Block SIGTERM so we won't be killed if the Zygote flushes the USAP pool.
+        blockSigTerm();
 
-        while (true) {
-            try {
-                sessionSocket = usapPoolSocket.accept();
+        LocalSocket sessionSocket = null;
+        if (argBuffer == null) {
+            // Read arguments from usapPoolSocket instead.
 
-                // Block SIGTERM so we won't be killed if the Zygote flushes the USAP pool.
-                blockSigTerm();
+            Process.setArgV0(Process.is64Bit() ? "usap64" : "usap32");
 
-                BufferedReader usapReader =
-                        new BufferedReader(new InputStreamReader(sessionSocket.getInputStream()));
-                usapOutputStream =
-                        new DataOutputStream(sessionSocket.getOutputStream());
+            // Change the priority to max before calling accept so we can respond to new
+            // specialization requests as quickly as possible.  This will be reverted to the
+            // default priority in the native specialization code.
+            boostUsapPriority();
 
-                peerCredentials = sessionSocket.getPeerCredentials();
+            while (true) {
+                ZygoteCommandBuffer tmpArgBuffer = null;
+                try {
+                    sessionSocket = usapPoolSocket.accept();
 
-                String[] argStrings = readArgumentList(usapReader);
-
-                if (argStrings != null) {
-                    args = new ZygoteArguments(argStrings);
-
+                    usapOutputStream =
+                            new DataOutputStream(sessionSocket.getOutputStream());
+                    Credentials peerCredentials = sessionSocket.getPeerCredentials();
+                    tmpArgBuffer = new ZygoteCommandBuffer(sessionSocket);
+                    args = ZygoteArguments.getInstance(argBuffer);
+                    applyUidSecurityPolicy(args, peerCredentials);
                     // TODO (chriswailes): Should this only be run for debug builds?
                     validateUsapCommand(args);
                     break;
-                } else {
-                    Log.e("USAP", "Truncated command received.");
-                    IoUtils.closeQuietly(sessionSocket);
-
-                    // Re-enable SIGTERM so the USAP can be flushed from the pool if necessary.
-                    unblockSigTerm();
+                } catch (Exception ex) {
+                    Log.e("USAP", ex.getMessage());
                 }
-            } catch (Exception ex) {
-                Log.e("USAP", ex.getMessage());
-                IoUtils.closeQuietly(sessionSocket);
-
                 // Re-enable SIGTERM so the USAP can be flushed from the pool if necessary.
                 unblockSigTerm();
+                IoUtils.closeQuietly(sessionSocket);
+                IoUtils.closeQuietly(tmpArgBuffer);
+                blockSigTerm();
             }
+        } else {
+            try {
+                args = ZygoteArguments.getInstance(argBuffer);
+            } catch (Exception ex) {
+                Log.e("AppStartup", ex.getMessage());
+                throw new AssertionError("Failed to parse application start command", ex);
+            }
+            // peerCredentials were checked in parent.
         }
-
+        if (args == null) {
+            throw new AssertionError("Empty command line");
+        }
         try {
-            // SIGTERM is blocked on loop exit.  This prevents a USAP that is specializing from
-            // being killed during a pool flush.
+            // SIGTERM is blocked here.  This prevents a USAP that is specializing from being
+            // killed during a pool flush.
 
-            setAppProcessName(args, "USAP");
-
-            applyUidSecurityPolicy(args, peerCredentials);
             applyDebuggerSystemProperty(args);
 
             int[][] rlimits = null;
@@ -696,53 +750,57 @@
                 rlimits = args.mRLimits.toArray(INT_ARRAY_2D);
             }
 
-            // This must happen before the SELinux policy for this process is
-            // changed when specializing.
-            try {
-                // Used by ZygoteProcess.zygoteSendArgsAndGetResult to fill in a
-                // Process.ProcessStartResult object.
-                usapOutputStream.writeInt(pid);
-            } catch (IOException ioEx) {
-                Log.e("USAP", "Failed to write response to session socket: "
-                        + ioEx.getMessage());
-                throw new RuntimeException(ioEx);
-            } finally {
-                IoUtils.closeQuietly(sessionSocket);
-
+            if (argBuffer == null) {
+                // This must happen before the SELinux policy for this process is
+                // changed when specializing.
                 try {
-                    // This socket is closed using Os.close due to an issue with the implementation
-                    // of LocalSocketImp.close().  Because the raw FD is created by init and then
-                    // loaded from an environment variable (as opposed to being created by the
-                    // LocalSocketImpl itself) the current implementation will not actually close
-                    // the underlying FD.
-                    //
-                    // See b/130309968 for discussion of this issue.
-                    Os.close(usapPoolSocket.getFileDescriptor());
-                } catch (ErrnoException ex) {
-                    Log.e("USAP", "Failed to close USAP pool socket");
-                    throw new RuntimeException(ex);
+                    // Used by ZygoteProcess.zygoteSendArgsAndGetResult to fill in a
+                    // Process.ProcessStartResult object.
+                    usapOutputStream.writeInt(pid);
+                } catch (IOException ioEx) {
+                    Log.e("USAP", "Failed to write response to session socket: "
+                            + ioEx.getMessage());
+                    throw new RuntimeException(ioEx);
+                } finally {
+                    try {
+                        // Since the raw FD is created by init and then loaded from an environment
+                        // variable (as opposed to being created by the LocalSocketImpl itself),
+                        // the LocalSocket/LocalSocketImpl does not own the Os-level socket. See
+                        // the spec for LocalSocket.createConnectedLocalSocket(FileDescriptor fd).
+                        // Thus closing the LocalSocket does not suffice. See b/130309968 for more
+                        // discussion.
+                        FileDescriptor fd = usapPoolSocket.getFileDescriptor();
+                        usapPoolSocket.close();
+                        Os.close(fd);
+                    } catch (ErrnoException | IOException ex) {
+                        Log.e("USAP", "Failed to close USAP pool socket");
+                        throw new RuntimeException(ex);
+                    }
                 }
             }
 
-            try {
-                ByteArrayOutputStream buffer =
-                        new ByteArrayOutputStream(Zygote.USAP_MANAGEMENT_MESSAGE_BYTES);
-                DataOutputStream outputStream = new DataOutputStream(buffer);
+            if (writePipe != null) {
+                try {
+                    ByteArrayOutputStream buffer =
+                            new ByteArrayOutputStream(Zygote.USAP_MANAGEMENT_MESSAGE_BYTES);
+                    DataOutputStream outputStream = new DataOutputStream(buffer);
 
-                // This is written as a long so that the USAP reporting pipe and USAP pool event FD
-                // handlers in ZygoteServer.runSelectLoop can be unified.  These two cases should
-                // both send/receive 8 bytes.
-                outputStream.writeLong(pid);
-                outputStream.flush();
-
-                Os.write(writePipe, buffer.toByteArray(), 0, buffer.size());
-            } catch (Exception ex) {
-                Log.e("USAP",
-                        String.format("Failed to write PID (%d) to pipe (%d): %s",
-                                pid, writePipe.getInt$(), ex.getMessage()));
-                throw new RuntimeException(ex);
-            } finally {
-                IoUtils.closeQuietly(writePipe);
+                    // This is written as a long so that the USAP reporting pipe and USAP pool
+                    // event FD handlers in ZygoteServer.runSelectLoop can be unified.  These two
+                    // cases should both send/receive 8 bytes.
+                    // TODO: Needs tweaking to handle the non-Usap invoke-with case, which expects
+                    // a different format.
+                    outputStream.writeLong(pid);
+                    outputStream.flush();
+                    Os.write(writePipe, buffer.toByteArray(), 0, buffer.size());
+                } catch (Exception ex) {
+                    Log.e("USAP",
+                            String.format("Failed to write PID (%d) to pipe (%d): %s",
+                                    pid, writePipe.getInt$(), ex.getMessage()));
+                    throw new RuntimeException(ex);
+                } finally {
+                    IoUtils.closeQuietly(writePipe);
+                }
             }
 
             specializeAppProcess(args.mUid, args.mGid, args.mGids,
@@ -849,13 +907,29 @@
         return nativeRemoveUsapTableEntry(usapPID);
     }
 
+    @CriticalNative
     private static native boolean nativeRemoveUsapTableEntry(int usapPID);
 
     /**
-     * uid 1000 (Process.SYSTEM_UID) may specify any uid &gt; 1000 in normal
+     * Return the minimum child uid that the given peer is allowed to create.
+     * uid 1000 (Process.SYSTEM_UID) may specify any uid &ge; 1000 in normal
      * operation. It may also specify any gid and setgroups() list it chooses.
      * In factory test mode, it may specify any UID.
-     *
+     */
+    static int minChildUid(Credentials peer) {
+        if (peer.getUid() == Process.SYSTEM_UID
+                && FactoryTest.getMode() == FactoryTest.FACTORY_TEST_OFF) {
+            /* In normal operation, SYSTEM_UID can only specify a restricted
+             * set of UIDs. In factory test mode, SYSTEM_UID may specify any uid.
+             */
+            return Process.SYSTEM_UID;
+        } else {
+            return 0;
+        }
+    }
+
+    /*
+     * Adjust uid and gid arguments, ensuring that the security policy is satisfied.
      * @param args non-null; zygote spawner arguments
      * @param peer non-null; peer credentials
      * @throws ZygoteSecurityException Indicates a security issue when applying the UID based
@@ -864,17 +938,10 @@
     static void applyUidSecurityPolicy(ZygoteArguments args, Credentials peer)
             throws ZygoteSecurityException {
 
-        if (peer.getUid() == Process.SYSTEM_UID) {
-            /* In normal operation, SYSTEM_UID can only specify a restricted
-             * set of UIDs. In factory test mode, SYSTEM_UID may specify any uid.
-             */
-            boolean uidRestricted = FactoryTest.getMode() == FactoryTest.FACTORY_TEST_OFF;
-
-            if (uidRestricted && args.mUidSpecified && (args.mUid < Process.SYSTEM_UID)) {
-                throw new ZygoteSecurityException(
-                        "System UID may not launch process with UID < "
-                        + Process.SYSTEM_UID);
-            }
+        if (args.mUidSpecified && (args.mUid < minChildUid(peer))) {
+            throw new ZygoteSecurityException(
+                    "System UID may not launch process with UID < "
+                    + Process.SYSTEM_UID);
         }
 
         // If not otherwise specified, uid and gid are inherited from peer
@@ -960,45 +1027,6 @@
     }
 
     /**
-     * Reads an argument list from the provided socket
-     * @return Argument list or null if EOF is reached
-     * @throws IOException passed straight through
-     */
-    static String[] readArgumentList(BufferedReader socketReader) throws IOException {
-        int argc;
-
-        try {
-            String argc_string = socketReader.readLine();
-
-            if (argc_string == null) {
-                // EOF reached.
-                return null;
-            }
-            argc = Integer.parseInt(argc_string);
-
-        } catch (NumberFormatException ex) {
-            Log.e("Zygote", "Invalid Zygote wire format: non-int at argc");
-            throw new IOException("Invalid wire format");
-        }
-
-        // See bug 1092107: large argc can be used for a DOS attack
-        if (argc > MAX_ZYGOTE_ARGC) {
-            throw new IOException("Max arg count exceeded");
-        }
-
-        String[] args = new String[argc];
-        for (int arg_index = 0; arg_index < argc; arg_index++) {
-            args[arg_index] = socketReader.readLine();
-            if (args[arg_index] == null) {
-                // We got an unexpected EOF.
-                throw new IOException("Truncated request");
-            }
-        }
-
-        return args;
-    }
-
-    /**
      * Creates a managed LocalServerSocket object using a file descriptor
      * created by an init.rc script.  The init scripts that specify the
      * sockets name can be found in system/core/rootdir.  The socket is bound
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index 32b808a..65b454d 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -16,8 +16,8 @@
 
 package com.android.internal.os;
 
+import java.io.EOFException;
 import java.util.ArrayList;
-import java.util.Arrays;
 
 /**
  * Handles argument parsing for args related to the zygote spawner.
@@ -245,20 +245,34 @@
     /**
      * Constructs instance and parses args
      *
-     * @param args zygote command-line args
+     * @param args zygote command-line args as ZygoteCommandBuffer, positioned after argument count.
      */
-    ZygoteArguments(String[] args) throws IllegalArgumentException {
-        parseArgs(args);
+    private ZygoteArguments(ZygoteCommandBuffer args, int argCount)
+            throws IllegalArgumentException, EOFException {
+        parseArgs(args, argCount);
+    }
+
+    /**
+     * Return a new ZygoteArguments reflecting the contents of the given ZygoteCommandBuffer. Return
+     * null if the ZygoteCommandBuffer was positioned at EOF. Assumes the buffer is initially
+     * positioned at the beginning of the command.
+     */
+    public static ZygoteArguments getInstance(ZygoteCommandBuffer args)
+            throws IllegalArgumentException, EOFException {
+        int argCount = args.getCount();
+        return argCount == 0 ? null : new ZygoteArguments(args, argCount);
     }
 
     /**
      * Parses the commandline arguments intended for the Zygote spawner (such as "--setuid=" and
-     * "--setgid=") and creates an array containing the remaining args.
+     * "--setgid=") and creates an array containing the remaining args. Return false if we were
+     * at EOF.
      *
      * Per security review bug #1112214, duplicate args are disallowed in critical cases to make
      * injection harder.
      */
-    private void parseArgs(String[] args) throws IllegalArgumentException {
+    private void parseArgs(ZygoteCommandBuffer args, int argCount)
+            throws IllegalArgumentException, EOFException {
         /*
          * See android.os.ZygoteProcess.zygoteSendArgsAndGetResult()
          * Presently the wire format to the zygote process is:
@@ -269,13 +283,13 @@
          * the child or -1 on failure.
          */
 
-        int curArg = 0;
-
+        String unprocessedArg = null;
+        int curArg = 0;  // Index of arg
         boolean seenRuntimeArgs = false;
-
         boolean expectRuntimeArgs = true;
-        for ( /* curArg */ ; curArg < args.length; curArg++) {
-            String arg = args[curArg];
+
+        for ( /* curArg */ ; curArg < argCount; ++curArg) {
+            String arg = args.nextArg();
 
             if (arg.equals("--")) {
                 curArg++;
@@ -367,7 +381,8 @@
                         "Duplicate arg specified");
                 }
                 try {
-                    mInvokeWith = args[++curArg];
+                    ++curArg;
+                    mInvokeWith = args.nextArg();
                 } catch (IndexOutOfBoundsException ex) {
                     throw new IllegalArgumentException(
                         "--invoke-with requires argument");
@@ -397,12 +412,14 @@
             } else if (arg.startsWith("--app-data-dir=")) {
                 mAppDataDir = getAssignmentValue(arg);
             } else if (arg.equals("--preload-app")) {
-                mPreloadApp = args[++curArg];
+                ++curArg;
+                mPreloadApp = args.nextArg();
             } else if (arg.equals("--preload-package")) {
-                mPreloadPackage = args[++curArg];
-                mPreloadPackageLibs = args[++curArg];
-                mPreloadPackageLibFileName = args[++curArg];
-                mPreloadPackageCacheKey = args[++curArg];
+                curArg += 4;
+                mPreloadPackage = args.nextArg();
+                mPreloadPackageLibs = args.nextArg();
+                mPreloadPackageLibFileName = args.nextArg();
+                mPreloadPackageCacheKey = args.nextArg();
             } else if (arg.equals("--preload-default")) {
                 mPreloadDefault = true;
                 expectRuntimeArgs = false;
@@ -411,8 +428,11 @@
             } else if (arg.equals("--set-api-denylist-exemptions")) {
                 // consume all remaining args; this is a stand-alone command, never included
                 // with the regular fork command.
-                mApiDenylistExemptions = Arrays.copyOfRange(args, curArg + 1, args.length);
-                curArg = args.length;
+                mApiDenylistExemptions = new String[argCount - curArg - 1];
+                ++curArg;
+                for (int i = 0; curArg < argCount; ++curArg, ++i) {
+                    mApiDenylistExemptions[i] = args.nextArg();
+                }
                 expectRuntimeArgs = false;
             } else if (arg.startsWith("--hidden-api-log-sampling-rate=")) {
                 String rateStr = getAssignmentValue(arg);
@@ -462,35 +482,46 @@
             } else if (arg.equals(Zygote.BIND_MOUNT_APP_DATA_DIRS)) {
                 mBindMountAppDataDirs = true;
             } else {
+                unprocessedArg = arg;
                 break;
             }
         }
+        // curArg is the index of the first unprocessed argument. That argument is either referenced
+        // by unprocessedArg or not read yet.
 
         if (mBootCompleted) {
-            if (args.length - curArg > 0) {
+            if (argCount > curArg) {
                 throw new IllegalArgumentException("Unexpected arguments after --boot-completed");
             }
         } else if (mAbiListQuery || mPidQuery) {
-            if (args.length - curArg > 0) {
+            if (argCount > curArg) {
                 throw new IllegalArgumentException("Unexpected arguments after --query-abi-list.");
             }
         } else if (mPreloadPackage != null) {
-            if (args.length - curArg > 0) {
+            if (argCount > curArg) {
                 throw new IllegalArgumentException(
                     "Unexpected arguments after --preload-package.");
             }
         } else if (mPreloadApp != null) {
-            if (args.length - curArg > 0) {
+            if (argCount > curArg) {
                 throw new IllegalArgumentException(
                     "Unexpected arguments after --preload-app.");
             }
         } else if (expectRuntimeArgs) {
             if (!seenRuntimeArgs) {
-                throw new IllegalArgumentException("Unexpected argument : " + args[curArg]);
+                throw new IllegalArgumentException("Unexpected argument : "
+                    + (unprocessedArg == null ? args.nextArg() : unprocessedArg));
             }
 
-            mRemainingArgs = new String[args.length - curArg];
-            System.arraycopy(args, curArg, mRemainingArgs, 0, mRemainingArgs.length);
+            mRemainingArgs = new String[argCount - curArg];
+            int i = 0;
+            if (unprocessedArg != null) {
+                mRemainingArgs[0] = unprocessedArg;
+                ++i;
+            }
+            for (; i < argCount - curArg; ++i) {
+                mRemainingArgs[i] = args.nextArg();
+            }
         }
 
         if (mStartChildZygote) {
diff --git a/core/java/com/android/internal/os/ZygoteCommandBuffer.java b/core/java/com/android/internal/os/ZygoteCommandBuffer.java
new file mode 100644
index 0000000..b61ae7a
--- /dev/null
+++ b/core/java/com/android/internal/os/ZygoteCommandBuffer.java
@@ -0,0 +1,187 @@
+/*
+ * 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.internal.os;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.LocalSocket;
+
+import java.io.FileDescriptor;
+import java.lang.ref.Reference;  // For reachabilityFence.
+
+/**
+ * A native-accessible buffer for Zygote commands. Designed to support repeated forking
+ * of applications without intervening memory allocation, thus keeping zygote memory
+ * as stable as possible.
+ * A ZygoteCommandBuffer may have an associated socket from which it can be refilled.
+ * Otherwise the contents are explicitly set by getInstance().
+ *
+ * NOT THREAD-SAFE. No methods may be called concurrently from multiple threads.
+ *
+ * Only one ZygoteCommandBuffer can exist at a time.
+ * Must be explicitly closed before being dropped.
+ * @hide
+ */
+class ZygoteCommandBuffer implements AutoCloseable {
+    private long mNativeBuffer;  // Not final so that we can clear it in close().
+
+    /**
+     * The command socket.
+     *
+     * mSocket is retained in the child process in "peer wait" mode, so
+     * that it closes when the child process terminates. In other cases,
+     * it is closed in the peer.
+     */
+    private final LocalSocket mSocket;
+    private final int mNativeSocket;
+
+    /**
+     * Constructs instance from file descriptor from which the command will be read.
+     * Only a single instance may be live in a given process. The native code checks.
+     *
+     * @param fd file descriptor to read from. The setCommand() method may be used if and only if
+     * fd is null.
+     */
+    ZygoteCommandBuffer(@Nullable LocalSocket socket) {
+        mSocket = socket;
+        if (socket == null) {
+            mNativeSocket = -1;
+        } else {
+            mNativeSocket = mSocket.getFileDescriptor().getInt$();
+        }
+        mNativeBuffer = getNativeBuffer(mNativeSocket);
+    }
+
+    /**
+     * Constructs an instance with explicitly supplied arguments and an invalid
+     * file descriptor. Can only be used for a single command.
+     */
+    ZygoteCommandBuffer(@NonNull String[] args) {
+        this((LocalSocket) null);
+        setCommand(args);
+    }
+
+
+    private static native long getNativeBuffer(int fd);
+
+    /**
+     * Deallocate native resources associated with the one and only command buffer, and prevent
+     * reuse. Subsequent calls to getInstance() will yield a new buffer.
+     * We do not close the associated socket, if any.
+     */
+    @Override
+    public void close() {
+        freeNativeBuffer(mNativeBuffer);
+        mNativeBuffer = 0;
+    }
+
+    private static native void freeNativeBuffer(long /* NativeCommandBuffer* */ nbuffer);
+
+    /**
+     * Read at least the first line of the next command into the buffer, return the argument count
+     * from that line. Assumes we are initially positioned at the beginning of the first line of
+     * the command. Leave the buffer positioned at the beginning of the second command line, i.e.
+     * the first argument. If the buffer has no associated file descriptor, we just reposition to
+     * the beginning of the buffer, and reread existing contents.  Returns zero if we started out
+     * at EOF.
+     */
+    int getCount() {
+        try {
+            return nativeGetCount(mNativeBuffer);
+        } finally {
+            // Make sure the mNativeSocket doesn't get closed due to early finalization.
+            Reference.reachabilityFence(mSocket);
+        }
+    }
+
+    private static native int nativeGetCount(long /* NativeCommandBuffer* */ nbuffer);
+
+
+    /*
+     * Set the buffer to contain the supplied sequence of arguments.
+     */
+    private void setCommand(String[] command) {
+        int nArgs = command.length;
+        insert(mNativeBuffer, Integer.toString(nArgs));
+        for (String s: command) {
+            insert(mNativeBuffer, s);
+        }
+        // Native code checks there is no socket; hence no reachabilityFence.
+    }
+
+    private static native void insert(long /* NativeCommandBuffer* */ nbuffer, String s);
+
+    /**
+     * Retrieve the next argument/line from the buffer, filling the buffer as necessary.
+     */
+    String nextArg() {
+        try {
+            return nativeNextArg(mNativeBuffer);
+        } finally {
+            Reference.reachabilityFence(mSocket);
+        }
+    }
+
+    private static native String nativeNextArg(long /* NativeCommandBuffer* */ nbuffer);
+
+    void readFullyAndReset() {
+        try {
+            nativeReadFullyAndReset(mNativeBuffer);
+        } finally {
+            Reference.reachabilityFence(mSocket);
+        }
+    }
+
+    private static native void nativeReadFullyAndReset(long /* NativeCommandBuffer* */ nbuffer);
+
+    /**
+     * Fork a child as specified by the current command in the buffer, and repeat this process
+     * after refilling the buffer, so long as the buffer clearly contains another fork command.
+     *
+     * @param zygoteSocket socket from which to obtain new connections when current one is
+     *         disconnected
+     * @param expectedUid Peer UID for current connection. We refuse to deal with requests from
+     *         a different UID.
+     * @param minUid the smallest uid that may be request for the child process.
+     * @param firstNiceName The name for the initial process to be forked. Used only for error
+     *         reporting.
+     *
+     * @return true in the child, false in the parent. In the parent case, the buffer is positioned
+     * at the beginning of a command that still needs to be processed.
+     */
+    boolean forkRepeatedly(FileDescriptor zygoteSocket, int expectedUid, int minUid,
+                       String firstNiceName) {
+        try {
+            return nativeForkRepeatedly(mNativeBuffer, zygoteSocket.getInt$(),
+                    expectedUid, minUid, firstNiceName);
+        } finally {
+            Reference.reachabilityFence(mSocket);
+            Reference.reachabilityFence(zygoteSocket);
+        }
+    }
+
+    /*
+     * Repeatedly fork children as above. It commonly does not return in the parent, but it may.
+     * @return true in the chaild, false in the parent if we encounter a command we couldn't handle.
+     */
+    private static native boolean nativeForkRepeatedly(long /* NativeCommandBuffer* */ nbuffer,
+                                                   int zygoteSocketRawFd,
+                                                   int expectedUid,
+                                                   int minUid,
+                                                   String firstNiceName);
+
+}
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 5a576ebb..37c7590 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -36,16 +36,15 @@
 import android.util.Log;
 
 import dalvik.system.VMRuntime;
+import dalvik.system.ZygoteHooks;
 
 import libcore.io.IoUtils;
 
-import java.io.BufferedReader;
 import java.io.ByteArrayInputStream;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.FileDescriptor;
 import java.io.IOException;
-import java.io.InputStreamReader;
 import java.nio.charset.StandardCharsets;
 import java.util.Base64;
 import java.util.concurrent.TimeUnit;
@@ -67,7 +66,6 @@
     private final LocalSocket mSocket;
     @UnsupportedAppUsage
     private final DataOutputStream mSocketOutStream;
-    private final BufferedReader mSocketReader;
     @UnsupportedAppUsage
     private final Credentials peer;
     private final String abiList;
@@ -85,9 +83,6 @@
         this.abiList = abiList;
 
         mSocketOutStream = new DataOutputStream(socket.getOutputStream());
-        mSocketReader =
-                new BufferedReader(
-                        new InputStreamReader(socket.getInputStream()), Zygote.SOCKET_BUFFER_SIZE);
 
         mSocket.setSoTimeout(CONNECTION_TIMEOUT_MILLIS);
 
@@ -111,178 +106,216 @@
     }
 
     /**
-     * Reads one start command from the command socket. If successful, a child is forked and a
+     * Reads a command from the command socket. If a child is successfully forked, a
      * {@code Runnable} that calls the childs main method (or equivalent) is returned in the child
      * process. {@code null} is always returned in the parent process (the zygote).
+     * If multipleOK is set, we may keep processing additional fork commands before returning.
      *
      * If the client closes the socket, an {@code EOF} condition is set, which callers can test
      * for by calling {@code ZygoteConnection.isClosedByPeer}.
      */
-    Runnable processOneCommand(ZygoteServer zygoteServer) {
-        String[] args;
+    Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) {
+        ZygoteArguments parsedArgs;
 
-        try {
-            args = Zygote.readArgumentList(mSocketReader);
-        } catch (IOException ex) {
-            throw new IllegalStateException("IOException on command socket", ex);
+        try (ZygoteCommandBuffer argBuffer = new ZygoteCommandBuffer(mSocket)) {
+            while (true) {
+                try {
+                    parsedArgs = ZygoteArguments.getInstance(argBuffer);
+                    // Keep argBuffer around, since we need it to fork.
+                } catch (IOException ex) {
+                    throw new IllegalStateException("IOException on command socket", ex);
+                }
+                if (parsedArgs == null) {
+                    isEof = true;
+                    return null;
+                }
+
+                int pid;
+                FileDescriptor childPipeFd = null;
+                FileDescriptor serverPipeFd = null;
+
+                if (parsedArgs.mBootCompleted) {
+                    handleBootCompleted();
+                    return null;
+                }
+
+                if (parsedArgs.mAbiListQuery) {
+                    handleAbiListQuery();
+                    return null;
+                }
+
+                if (parsedArgs.mPidQuery) {
+                    handlePidQuery();
+                    return null;
+                }
+
+                if (parsedArgs.mUsapPoolStatusSpecified) {
+                    // Handle this once we've released the argBuffer, to avoid opening a second one.
+                    break;
+                }
+
+                if (parsedArgs.mPreloadDefault) {
+                    handlePreload();
+                    return null;
+                }
+
+                if (parsedArgs.mPreloadPackage != null) {
+                    handlePreloadPackage(parsedArgs.mPreloadPackage,
+                            parsedArgs.mPreloadPackageLibs,
+                            parsedArgs.mPreloadPackageLibFileName,
+                            parsedArgs.mPreloadPackageCacheKey);
+                    return null;
+                }
+
+                if (canPreloadApp() && parsedArgs.mPreloadApp != null) {
+                    byte[] rawParcelData = Base64.getDecoder().decode(parsedArgs.mPreloadApp);
+                    Parcel appInfoParcel = Parcel.obtain();
+                    appInfoParcel.unmarshall(rawParcelData, 0, rawParcelData.length);
+                    appInfoParcel.setDataPosition(0);
+                    ApplicationInfo appInfo =
+                            ApplicationInfo.CREATOR.createFromParcel(appInfoParcel);
+                    appInfoParcel.recycle();
+                    if (appInfo != null) {
+                        handlePreloadApp(appInfo);
+                    } else {
+                        throw new IllegalArgumentException("Failed to deserialize --preload-app");
+                    }
+                    return null;
+                }
+
+                if (parsedArgs.mApiDenylistExemptions != null) {
+                    return handleApiDenylistExemptions(zygoteServer,
+                            parsedArgs.mApiDenylistExemptions);
+                }
+
+                if (parsedArgs.mHiddenApiAccessLogSampleRate != -1
+                        || parsedArgs.mHiddenApiAccessStatslogSampleRate != -1) {
+                    return handleHiddenApiAccessLogSampleRate(zygoteServer,
+                            parsedArgs.mHiddenApiAccessLogSampleRate,
+                            parsedArgs.mHiddenApiAccessStatslogSampleRate);
+                }
+
+                if (parsedArgs.mPermittedCapabilities != 0
+                        || parsedArgs.mEffectiveCapabilities != 0) {
+                    throw new ZygoteSecurityException("Client may not specify capabilities: "
+                            + "permitted=0x" + Long.toHexString(parsedArgs.mPermittedCapabilities)
+                            + ", effective=0x"
+                            + Long.toHexString(parsedArgs.mEffectiveCapabilities));
+                }
+
+                Zygote.applyUidSecurityPolicy(parsedArgs, peer);
+                Zygote.applyInvokeWithSecurityPolicy(parsedArgs, peer);
+
+                Zygote.applyDebuggerSystemProperty(parsedArgs);
+                Zygote.applyInvokeWithSystemProperty(parsedArgs);
+
+                int[][] rlimits = null;
+
+                if (parsedArgs.mRLimits != null) {
+                    rlimits = parsedArgs.mRLimits.toArray(Zygote.INT_ARRAY_2D);
+                }
+
+                int[] fdsToIgnore = null;
+
+                if (parsedArgs.mInvokeWith != null) {
+                    try {
+                        FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
+                        childPipeFd = pipeFds[1];
+                        serverPipeFd = pipeFds[0];
+                        Os.fcntlInt(childPipeFd, F_SETFD, 0);
+                        fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()};
+                    } catch (ErrnoException errnoEx) {
+                        throw new IllegalStateException("Unable to set up pipe for invoke-with",
+                                errnoEx);
+                    }
+                }
+
+                /*
+                 * In order to avoid leaking descriptors to the Zygote child,
+                 * the native code must close the two Zygote socket descriptors
+                 * in the child process before it switches from Zygote-root to
+                 * the UID and privileges of the application being launched.
+                 *
+                 * In order to avoid "bad file descriptor" errors when the
+                 * two LocalSocket objects are closed, the Posix file
+                 * descriptors are released via a dup2() call which closes
+                 * the socket and substitutes an open descriptor to /dev/null.
+                 */
+
+                int [] fdsToClose = { -1, -1 };
+
+                FileDescriptor fd = mSocket.getFileDescriptor();
+
+                if (fd != null) {
+                    fdsToClose[0] = fd.getInt$();
+                }
+
+                FileDescriptor zygoteFd = zygoteServer.getZygoteSocketFileDescriptor();
+
+                if (zygoteFd != null) {
+                    fdsToClose[1] = zygoteFd.getInt$();
+                }
+
+                if (parsedArgs.mInvokeWith != null || parsedArgs.mStartChildZygote
+                        || !multipleOK || peer.getUid() != Process.SYSTEM_UID) {
+                    // Continue using old code for now. TODO: Handle these cases in the other path.
+                    pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid,
+                            parsedArgs.mGids, parsedArgs.mRuntimeFlags, rlimits,
+                            parsedArgs.mMountExternal, parsedArgs.mSeInfo, parsedArgs.mNiceName,
+                            fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
+                            parsedArgs.mInstructionSet, parsedArgs.mAppDataDir,
+                            parsedArgs.mIsTopApp, parsedArgs.mPkgDataInfoList,
+                            parsedArgs.mWhitelistedDataInfoList, parsedArgs.mBindMountAppDataDirs,
+                            parsedArgs.mBindMountAppStorageDirs);
+
+                    try {
+                        if (pid == 0) {
+                            // in child
+                            zygoteServer.setForkChild();
+
+                            zygoteServer.closeServerSocket();
+                            IoUtils.closeQuietly(serverPipeFd);
+                            serverPipeFd = null;
+
+                            return handleChildProc(parsedArgs, childPipeFd,
+                                    parsedArgs.mStartChildZygote);
+                        } else {
+                            // In the parent. A pid < 0 indicates a failure and will be handled in
+                            // handleParentProc.
+                            IoUtils.closeQuietly(childPipeFd);
+                            childPipeFd = null;
+                            handleParentProc(pid, serverPipeFd);
+                            return null;
+                        }
+                    } finally {
+                        IoUtils.closeQuietly(childPipeFd);
+                        IoUtils.closeQuietly(serverPipeFd);
+                    }
+                } else {
+                    ZygoteHooks.preFork();
+                    Runnable result = Zygote.forkSimpleApps(argBuffer,
+                            zygoteServer.getZygoteSocketFileDescriptor(),
+                            peer.getUid(), Zygote.minChildUid(peer), parsedArgs.mNiceName);
+                    if (result == null) {
+                        // parent; we finished some number of forks. Result is Boolean.
+                        // We already did the equivalent of handleParentProc().
+                        ZygoteHooks.postForkCommon();
+                        // argBuffer contains a command not understood by forksimpleApps.
+                        continue;
+                    } else {
+                        // child; result is a Runnable.
+                        zygoteServer.setForkChild();
+                        Zygote.setAppProcessName(parsedArgs, TAG);  // ??? Necessary?
+                        return result;
+                    }
+                }
+            }
         }
-
-        // readArgumentList returns null only when it has reached EOF with no available
-        // data to read. This will only happen when the remote socket has disconnected.
-        if (args == null) {
-            isEof = true;
-            return null;
-        }
-
-        int pid;
-        FileDescriptor childPipeFd = null;
-        FileDescriptor serverPipeFd = null;
-
-        ZygoteArguments parsedArgs = new ZygoteArguments(args);
-
-        if (parsedArgs.mBootCompleted) {
-            handleBootCompleted();
-            return null;
-        }
-
-        if (parsedArgs.mAbiListQuery) {
-            handleAbiListQuery();
-            return null;
-        }
-
-        if (parsedArgs.mPidQuery) {
-            handlePidQuery();
-            return null;
-        }
-
         if (parsedArgs.mUsapPoolStatusSpecified) {
+            // Now that we've released argBuffer:
             return handleUsapPoolStatusChange(zygoteServer, parsedArgs.mUsapPoolEnabled);
         }
-
-        if (parsedArgs.mPreloadDefault) {
-            handlePreload();
-            return null;
-        }
-
-        if (parsedArgs.mPreloadPackage != null) {
-            handlePreloadPackage(parsedArgs.mPreloadPackage, parsedArgs.mPreloadPackageLibs,
-                    parsedArgs.mPreloadPackageLibFileName, parsedArgs.mPreloadPackageCacheKey);
-            return null;
-        }
-
-        if (canPreloadApp() && parsedArgs.mPreloadApp != null) {
-            byte[] rawParcelData = Base64.getDecoder().decode(parsedArgs.mPreloadApp);
-            Parcel appInfoParcel = Parcel.obtain();
-            appInfoParcel.unmarshall(rawParcelData, 0, rawParcelData.length);
-            appInfoParcel.setDataPosition(0);
-            ApplicationInfo appInfo = ApplicationInfo.CREATOR.createFromParcel(appInfoParcel);
-            appInfoParcel.recycle();
-            if (appInfo != null) {
-                handlePreloadApp(appInfo);
-            } else {
-                throw new IllegalArgumentException("Failed to deserialize --preload-app");
-            }
-            return null;
-        }
-
-        if (parsedArgs.mApiDenylistExemptions != null) {
-            return handleApiDenylistExemptions(zygoteServer, parsedArgs.mApiDenylistExemptions);
-        }
-
-        if (parsedArgs.mHiddenApiAccessLogSampleRate != -1
-                || parsedArgs.mHiddenApiAccessStatslogSampleRate != -1) {
-            return handleHiddenApiAccessLogSampleRate(zygoteServer,
-                    parsedArgs.mHiddenApiAccessLogSampleRate,
-                    parsedArgs.mHiddenApiAccessStatslogSampleRate);
-        }
-
-        if (parsedArgs.mPermittedCapabilities != 0 || parsedArgs.mEffectiveCapabilities != 0) {
-            throw new ZygoteSecurityException("Client may not specify capabilities: "
-                    + "permitted=0x" + Long.toHexString(parsedArgs.mPermittedCapabilities)
-                    + ", effective=0x" + Long.toHexString(parsedArgs.mEffectiveCapabilities));
-        }
-
-        Zygote.applyUidSecurityPolicy(parsedArgs, peer);
-        Zygote.applyInvokeWithSecurityPolicy(parsedArgs, peer);
-
-        Zygote.applyDebuggerSystemProperty(parsedArgs);
-        Zygote.applyInvokeWithSystemProperty(parsedArgs);
-
-        int[][] rlimits = null;
-
-        if (parsedArgs.mRLimits != null) {
-            rlimits = parsedArgs.mRLimits.toArray(Zygote.INT_ARRAY_2D);
-        }
-
-        int[] fdsToIgnore = null;
-
-        if (parsedArgs.mInvokeWith != null) {
-            try {
-                FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
-                childPipeFd = pipeFds[1];
-                serverPipeFd = pipeFds[0];
-                Os.fcntlInt(childPipeFd, F_SETFD, 0);
-                fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()};
-            } catch (ErrnoException errnoEx) {
-                throw new IllegalStateException("Unable to set up pipe for invoke-with", errnoEx);
-            }
-        }
-
-        /*
-         * In order to avoid leaking descriptors to the Zygote child,
-         * the native code must close the two Zygote socket descriptors
-         * in the child process before it switches from Zygote-root to
-         * the UID and privileges of the application being launched.
-         *
-         * In order to avoid "bad file descriptor" errors when the
-         * two LocalSocket objects are closed, the Posix file
-         * descriptors are released via a dup2() call which closes
-         * the socket and substitutes an open descriptor to /dev/null.
-         */
-
-        int [] fdsToClose = { -1, -1 };
-
-        FileDescriptor fd = mSocket.getFileDescriptor();
-
-        if (fd != null) {
-            fdsToClose[0] = fd.getInt$();
-        }
-
-        fd = zygoteServer.getZygoteSocketFileDescriptor();
-
-        if (fd != null) {
-            fdsToClose[1] = fd.getInt$();
-        }
-
-        pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,
-                parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
-                parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
-                parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mIsTopApp,
-                parsedArgs.mPkgDataInfoList, parsedArgs.mWhitelistedDataInfoList,
-                parsedArgs.mBindMountAppDataDirs, parsedArgs.mBindMountAppStorageDirs);
-
-        try {
-            if (pid == 0) {
-                // in child
-                zygoteServer.setForkChild();
-
-                zygoteServer.closeServerSocket();
-                IoUtils.closeQuietly(serverPipeFd);
-                serverPipeFd = null;
-
-                return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote);
-            } else {
-                // In the parent. A pid < 0 indicates a failure and will be handled in
-                // handleParentProc.
-                IoUtils.closeQuietly(childPipeFd);
-                childPipeFd = null;
-                handleParentProc(pid, serverPipeFd);
-                return null;
-            }
-        } finally {
-            IoUtils.closeQuietly(childPipeFd);
-            IoUtils.closeQuietly(serverPipeFd);
-        }
+        throw new AssertionError("Shouldn't get here");
     }
 
     private void handleAbiListQuery() {
@@ -557,7 +590,7 @@
 
                     if (res > 0) {
                         if ((fds[0].revents & POLLIN) != 0) {
-                            // Only read one byte, so as not to block.
+                            // Only read one byte, so as not to block. Really needed?
                             int readBytes = android.system.Os.read(pipeFd, data, dataIndex, 1);
                             if (readBytes < 0) {
                                 throw new RuntimeException("Some error");
diff --git a/core/java/com/android/internal/os/ZygoteConnectionConstants.java b/core/java/com/android/internal/os/ZygoteConnectionConstants.java
index 506e39f..0c1cd6d 100644
--- a/core/java/com/android/internal/os/ZygoteConnectionConstants.java
+++ b/core/java/com/android/internal/os/ZygoteConnectionConstants.java
@@ -31,9 +31,6 @@
      */
     public static final int CONNECTION_TIMEOUT_MILLIS = 1000;
 
-    /** max number of arguments that a connection can specify */
-    public static final int MAX_ZYGOTE_ARGC = 1024;
-
     /**
      * Wait time for a wrapped app to report back its pid.
      *
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index f2ed50e..d5b778e 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -65,6 +65,7 @@
 import libcore.io.IoUtils;
 
 import java.io.BufferedReader;
+import java.io.EOFException;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
@@ -782,7 +783,13 @@
         int pid;
 
         try {
-            parsedArgs = new ZygoteArguments(args);
+            ZygoteCommandBuffer commandBuffer = new ZygoteCommandBuffer(args);
+            try {
+                parsedArgs = ZygoteArguments.getInstance(commandBuffer);
+            } catch (EOFException e) {
+                throw new AssertionError("Unexpected argument error for forking system server", e);
+            }
+            commandBuffer.close();
             Zygote.applyDebuggerSystemProperty(parsedArgs);
             Zygote.applyInvokeWithSystemProperty(parsedArgs);
 
@@ -861,7 +868,7 @@
      * into new processes are required to either set the priority to the default value or terminate
      * before executing any non-system code.  The native side of this occurs in SpecializeCommon,
      * while the Java Language priority is changed in ZygoteInit.handleSystemServerProcess,
-     * ZygoteConnection.handleChildProc, and Zygote.usapMain.
+     * ZygoteConnection.handleChildProc, and Zygote.childMain.
      *
      * @param argv  Command line arguments used to specify the Zygote's configuration.
      */
diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java
index 585ddf6..f71b314 100644
--- a/core/java/com/android/internal/os/ZygoteServer.java
+++ b/core/java/com/android/internal/os/ZygoteServer.java
@@ -337,7 +337,7 @@
      * @param sessionSocketRawFDs  Anonymous session sockets that are currently open
      * @return In the Zygote process this function will always return null; in unspecialized app
      *         processes this function will return a Runnable object representing the new
-     *         application that is passed up from usapMain.
+     *         application that is passed up from childMain (the usap's main wait loop).
      */
 
     Runnable fillUsapPool(int[] sessionSocketRawFDs, boolean isPriorityRefill) {
@@ -420,6 +420,7 @@
      * Runs the zygote process's select loop. Accepts new connections as
      * they happen, and reads commands from connections one spawn-request's
      * worth at a time.
+     * @param abiList list of ABIs supported by this zygote.
      */
     Runnable runSelectLoop(String abiList) {
         ArrayList<FileDescriptor> socketFDs = new ArrayList<>();
@@ -537,22 +538,23 @@
 
                     if (pollIndex == 0) {
                         // Zygote server socket
-
                         ZygoteConnection newPeer = acceptCommandPeer(abiList);
                         peers.add(newPeer);
                         socketFDs.add(newPeer.getFileDescriptor());
-
                     } else if (pollIndex < usapPoolEventFDIndex) {
                         // Session socket accepted from the Zygote server socket
 
                         try {
                             ZygoteConnection connection = peers.get(pollIndex);
-                            final Runnable command = connection.processOneCommand(this);
+                            boolean multipleForksOK = !isUsapPoolEnabled()
+                                    && ZygoteHooks.indefiniteThreadSuspensionOK();
+                            final Runnable command =
+                                    connection.processCommand(this, multipleForksOK);
 
                             // TODO (chriswailes): Is this extra check necessary?
                             if (mIsForkChild) {
                                 // We're in the child. We should always have a command to run at
-                                // this stage if processOneCommand hasn't called "exec".
+                                // this stage if processCommand hasn't called "exec".
                                 if (command == null) {
                                     throw new IllegalStateException("command == null");
                                 }
@@ -565,7 +567,7 @@
                                 }
 
                                 // We don't know whether the remote side of the socket was closed or
-                                // not until we attempt to read from it from processOneCommand. This
+                                // not until we attempt to read from it from processCommand. This
                                 // shows up as a regular POLLIN event in our regular processing
                                 // loop.
                                 if (connection.isClosedByPeer()) {
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 9840013..9a91d20 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -124,6 +124,7 @@
 import com.android.internal.widget.FloatingToolbar;
 
 import java.util.List;
+import java.util.function.Consumer;
 
 /** @hide */
 public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
@@ -282,14 +283,19 @@
     private final Paint mLegacyNavigationBarBackgroundPaint = new Paint();
     private Insets mBackgroundInsets = Insets.NONE;
     private Insets mLastBackgroundInsets = Insets.NONE;
-    private int mLastBackgroundBlurRadius = 0;
     private boolean mDrawLegacyNavigationBarBackground;
 
     private PendingInsetsController mPendingInsetsController = new PendingInsetsController();
+
+    private int mOriginalBackgroundBlurRadius = 0;
+    private int mBackgroundBlurRadius = 0;
+    private int mLastBackgroundBlurRadius = 0;
+    private boolean mCrossWindowBlurEnabled;
     private final ViewTreeObserver.OnPreDrawListener mBackgroundBlurOnPreDrawListener = () -> {
-        updateBackgroundBlur();
+        updateBackgroundBlurCorners();
         return true;
     };
+    private Consumer<Boolean> mCrossWindowBlurEnabledListener;
 
     DecorView(Context context, int featureId, PhoneWindow window,
             WindowManager.LayoutParams params) {
@@ -1272,23 +1278,17 @@
         }
 
         if (mBackgroundInsets.equals(mLastBackgroundInsets)
-                && mWindow.mBackgroundBlurRadius == mLastBackgroundBlurRadius
+                && mBackgroundBlurRadius == mLastBackgroundBlurRadius
                 && mLastOriginalBackgroundDrawable == mOriginalBackgroundDrawable) {
             return;
         }
 
         Drawable destDrawable = mOriginalBackgroundDrawable;
-        if (mWindow.mBackgroundBlurRadius > 0 && getViewRootImpl() != null
-                && mWindow.isTranslucent()) {
-            if (mBackgroundBlurDrawable == null) {
-                mBackgroundBlurDrawable = getViewRootImpl().createBackgroundBlurDrawable();
-            }
+        if (mBackgroundBlurRadius > 0) {
             destDrawable = new LayerDrawable(new Drawable[] {mBackgroundBlurDrawable,
                                                              mOriginalBackgroundDrawable});
-            mLastBackgroundBlurRadius = mWindow.mBackgroundBlurRadius;
         }
 
-
         if (destDrawable != null && !mBackgroundInsets.equals(Insets.NONE)) {
             destDrawable = new InsetDrawable(destDrawable,
                     mBackgroundInsets.left, mBackgroundInsets.top,
@@ -1309,23 +1309,60 @@
         super.setBackgroundDrawable(destDrawable);
 
         mLastBackgroundInsets = mBackgroundInsets;
+        mLastBackgroundBlurRadius = mBackgroundBlurRadius;
         mLastOriginalBackgroundDrawable = mOriginalBackgroundDrawable;
     }
 
-    private void updateBackgroundBlur() {
+    private void updateBackgroundBlurCorners() {
         if (mBackgroundBlurDrawable == null) return;
 
+        float cornerRadius = 0;
         // If the blur radius is 0, the blur region won't be sent to surface flinger, so we don't
         // need to calculate the corner radius.
-        if (mWindow.mBackgroundBlurRadius > 0) {
-            if (mOriginalBackgroundDrawable != null) {
-                final Outline outline = new Outline();
-                mOriginalBackgroundDrawable.getOutline(outline);
-                mBackgroundBlurDrawable.setCornerRadius(outline.mMode == Outline.MODE_ROUND_RECT
-                                                           ? outline.getRadius() : 0);
-            }
+        if (mBackgroundBlurRadius != 0 && mOriginalBackgroundDrawable != null) {
+            final Outline outline = new Outline();
+            mOriginalBackgroundDrawable.getOutline(outline);
+            cornerRadius = outline.mMode == Outline.MODE_ROUND_RECT ? outline.getRadius() : 0;
         }
-        mBackgroundBlurDrawable.setBlurRadius(mWindow.mBackgroundBlurRadius);
+        mBackgroundBlurDrawable.setCornerRadius(cornerRadius);
+    }
+
+    private void updateBackgroundBlurRadius() {
+        if (getViewRootImpl() == null) return;
+
+        mBackgroundBlurRadius = mCrossWindowBlurEnabled && mWindow.isTranslucent()
+                ? mOriginalBackgroundBlurRadius : 0;
+        if (mBackgroundBlurDrawable == null && mBackgroundBlurRadius > 0) {
+            mBackgroundBlurDrawable = getViewRootImpl().createBackgroundBlurDrawable();
+        }
+
+        if (mBackgroundBlurDrawable != null) {
+            mBackgroundBlurDrawable.setBlurRadius(mBackgroundBlurRadius);
+            updateBackgroundDrawable();
+        }
+    }
+
+    void setBackgroundBlurRadius(int blurRadius) {
+        mOriginalBackgroundBlurRadius = blurRadius;
+        if (blurRadius > 0) {
+            if (mCrossWindowBlurEnabledListener == null) {
+                mCrossWindowBlurEnabledListener = enabled -> {
+                    mCrossWindowBlurEnabled = enabled;
+                    updateBackgroundBlurRadius();
+                };
+                getContext().getSystemService(WindowManager.class)
+                        .addCrossWindowBlurEnabledListener(mCrossWindowBlurEnabledListener);
+                getViewTreeObserver().addOnPreDrawListener(mBackgroundBlurOnPreDrawListener);
+            } else {
+                updateBackgroundBlurRadius();
+            }
+        } else if (mCrossWindowBlurEnabledListener != null) {
+            mCrossWindowBlurEnabledListener = null;
+            getContext().getSystemService(WindowManager.class)
+                    .removeCrossWindowBlurEnabledListener(mCrossWindowBlurEnabledListener);
+            getViewTreeObserver().removeOnPreDrawListener(mBackgroundBlurOnPreDrawListener);
+            updateBackgroundBlurRadius();
+        }
     }
 
     @Override
@@ -1758,9 +1795,6 @@
             cb.onAttachedToWindow();
         }
 
-        getViewTreeObserver().addOnPreDrawListener(mBackgroundBlurOnPreDrawListener);
-        updateBackgroundDrawable();
-
         if (mFeatureId == -1) {
             /*
              * The main window has been attached, try to restore any panels
@@ -1782,6 +1816,9 @@
             // renderer about it.
             mBackdropFrameRenderer.onConfigurationChange();
         }
+
+        updateBackgroundBlurRadius();
+
         mWindow.onViewRootImplSet(getViewRootImpl());
     }
 
@@ -1794,8 +1831,6 @@
             cb.onDetachedFromWindow();
         }
 
-        getViewTreeObserver().removeOnPreDrawListener(mBackgroundBlurOnPreDrawListener);
-
         if (mWindow.mDecorContentParent != null) {
             mWindow.mDecorContentParent.dismissPopups();
         }
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index d06413c..6049486 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -75,6 +75,7 @@
 import android.util.SparseArray;
 import android.util.TypedValue;
 import android.view.ContextThemeWrapper;
+import android.view.CrossWindowBlurListeners;
 import android.view.Gravity;
 import android.view.IRotationWatcher.Stub;
 import android.view.IScrollCaptureCallbacks;
@@ -258,7 +259,7 @@
     Drawable mBackgroundDrawable = null;
     Drawable mBackgroundFallbackDrawable = null;
 
-    int mBackgroundBlurRadius = 0;
+    private int mBackgroundBlurRadius = 0;
 
     private boolean mLoadElevation = true;
     private float mElevation;
@@ -1527,9 +1528,11 @@
     @Override
     public final void setBackgroundBlurRadius(int blurRadius) {
         super.setBackgroundBlurRadius(blurRadius);
-        if (getContext().getPackageManager().hasSystemFeature(
-                    PackageManager.FEATURE_CROSS_LAYER_BLUR)) {
-            mBackgroundBlurRadius = Math.max(blurRadius, 0);
+        if (CrossWindowBlurListeners.CROSS_WINDOW_BLUR_SUPPORTED) {
+            if (mBackgroundBlurRadius != Math.max(blurRadius, 0)) {
+                mBackgroundBlurRadius = Math.max(blurRadius, 0);
+                mDecor.setBackgroundBlurRadius(mBackgroundBlurRadius);
+            }
         }
     }
 
@@ -2556,8 +2559,8 @@
                 params.flags |= WindowManager.LayoutParams.FLAG_BLUR_BEHIND;
             }
 
-            params.blurBehindRadius = a.getDimensionPixelSize(
-                    android.R.styleable.Window_windowBlurBehindRadius, 0);
+            params.setBlurBehindRadius(a.getDimensionPixelSize(
+                    android.R.styleable.Window_windowBlurBehindRadius, 0));
         }
 
         setBackgroundBlurRadius(a.getDimensionPixelSize(
diff --git a/core/java/com/android/internal/power/MeasuredEnergyStats.java b/core/java/com/android/internal/power/MeasuredEnergyStats.java
index d7b4d78..d49203c 100644
--- a/core/java/com/android/internal/power/MeasuredEnergyStats.java
+++ b/core/java/com/android/internal/power/MeasuredEnergyStats.java
@@ -193,34 +193,30 @@
         return mAccumulatedEnergiesMicroJoules.length;
     }
 
-    // TODO: Get rid of the 'accumulate' boolean. It's always true.
     /** Updates the given standard energy bucket with the given energy if accumulate is true. */
-    public void updateStandardBucket(@StandardEnergyBucket int bucket, long energyDeltaUJ,
-            boolean accumulate) {
+    public void updateStandardBucket(@StandardEnergyBucket int bucket, long energyDeltaUJ) {
         checkValidStandardBucket(bucket);
-        updateEntry(bucket, energyDeltaUJ, accumulate);
+        updateEntry(bucket, energyDeltaUJ);
     }
 
     /** Updates the given custom energy bucket with the given energy if accumulate is true. */
-    public void updateCustomBucket(int customBucket, long energyDeltaUJ, boolean accumulate) {
+    public void updateCustomBucket(int customBucket, long energyDeltaUJ) {
         if (!isValidCustomBucket(customBucket)) {
             Slog.e(TAG, "Attempted to update invalid custom bucket " + customBucket);
             return;
         }
         final int index = customBucketToIndex(customBucket);
-        updateEntry(index, energyDeltaUJ, accumulate);
+        updateEntry(index, energyDeltaUJ);
     }
 
     /** Updates the given index with the given energy if accumulate is true. */
-    private void updateEntry(int index, long energyDeltaUJ, boolean accumulate) {
-        if (accumulate) {
-            if (mAccumulatedEnergiesMicroJoules[index] >= 0L) {
-                mAccumulatedEnergiesMicroJoules[index] += energyDeltaUJ;
-            } else {
-                Slog.wtf(TAG, "Attempting to add " + energyDeltaUJ + " to unavailable bucket "
-                        + getBucketName(index) + " whose value was "
-                        + mAccumulatedEnergiesMicroJoules[index]);
-            }
+    private void updateEntry(int index, long energyDeltaUJ) {
+        if (mAccumulatedEnergiesMicroJoules[index] >= 0L) {
+            mAccumulatedEnergiesMicroJoules[index] += energyDeltaUJ;
+        } else {
+            Slog.wtf(TAG, "Attempting to add " + energyDeltaUJ + " to unavailable bucket "
+                    + getBucketName(index) + " whose value was "
+                    + mAccumulatedEnergiesMicroJoules[index]);
         }
     }
 
diff --git a/core/java/com/android/internal/power/TEST_MAPPING b/core/java/com/android/internal/power/TEST_MAPPING
new file mode 100644
index 0000000..96f31bc
--- /dev/null
+++ b/core/java/com/android/internal/power/TEST_MAPPING
@@ -0,0 +1,19 @@
+{
+  "presubmit": [
+    {
+      "name": "FrameworksCoreTests",
+      "options": [
+        { "include-filter": "com.android.internal.os.BatteryStatsTests" },
+        { "exclude-annotation": "com.android.internal.os.SkipPresubmit" }
+      ]
+    },
+    {
+      "name": "FrameworksServicesTests",
+      "options": [
+        { "include-filter": "com.android.server.am.BatteryStatsServiceTest" },
+        { "include-filter": "com.android.server.am.MeasuredEnergySnapshotTest" },
+        { "include-filter": "com.android.server.am.BatteryExternalStatsWorkerTest" }
+      ]
+    }
+  ]
+}
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 7edc6c8..fde48e8 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -67,7 +67,7 @@
     void onNotificationError(String pkg, String tag, int id,
             int uid, int initialPid, String message, int userId);
     void onClearAllNotifications(int userId);
-    void onNotificationClear(String pkg, String tag, int id, int userId, String key,
+    void onNotificationClear(String pkg, int userId, String key,
             int dismissalSurface, int dismissalSentiment, in NotificationVisibility nv);
     void onNotificationVisibilityChanged( in NotificationVisibility[] newlyVisibleKeys,
             in NotificationVisibility[] noLongerVisibleKeys);
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index f7d440d..95e0a3b 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -94,6 +94,6 @@
     void notifyBarringInfoChanged(int slotIndex, int subId, in BarringInfo barringInfo);
     void notifyPhysicalChannelConfigForSubscriber(in int subId,
             in List<PhysicalChannelConfig> configs);
-    void notifyDataEnabled(boolean enabled, int reason);
+    void notifyDataEnabled(in int phoneId, int subId, boolean enabled, int reason);
     void notifyAllowedNetworkTypesChanged(in int phoneId, in int subId, in Map allowedNetworkTypeList);
 }
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index ef2275d..ab0149f 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -30,6 +30,7 @@
 import android.view.InsetsSourceControl;
 import android.view.InsetsState;
 import android.view.PointerIcon;
+import android.view.ScrollCaptureResponse;
 import android.view.WindowInsets.Type.InsetsType;
 import android.window.ClientWindowFrames;
 
@@ -160,7 +161,9 @@
     @Override
     public void requestScrollCapture(IScrollCaptureCallbacks callbacks) {
         try {
-            callbacks.onUnavailable();
+            callbacks.onScrollCaptureResponse(
+                    new ScrollCaptureResponse.Builder().setDescription("Not Implemented").build());
+
         } catch (RemoteException ex) {
             // ignore
         }
diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
index 8d82e33..c336373 100644
--- a/core/java/com/android/internal/view/IInputMethod.aidl
+++ b/core/java/com/android/internal/view/IInputMethod.aidl
@@ -35,8 +35,7 @@
  * {@hide}
  */
 oneway interface IInputMethod {
-    void initializeInternal(IBinder token, int displayId, IInputMethodPrivilegedOperations privOps,
-             int configChanges);
+    void initializeInternal(IBinder token, int displayId, IInputMethodPrivilegedOperations privOps);
 
     void onCreateInlineSuggestionsRequest(in InlineSuggestionsRequestInfo requestInfo,
             in IInlineSuggestionsRequestCallback cb);
diff --git a/core/java/com/android/internal/view/ScrollCaptureViewSupport.java b/core/java/com/android/internal/view/ScrollCaptureViewSupport.java
index 85fa791..a41511b 100644
--- a/core/java/com/android/internal/view/ScrollCaptureViewSupport.java
+++ b/core/java/com/android/internal/view/ScrollCaptureViewSupport.java
@@ -16,15 +16,19 @@
 
 package com.android.internal.view;
 
+import android.annotation.UiThread;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
 import android.graphics.HardwareRenderer;
 import android.graphics.Matrix;
 import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.RenderNode;
-import android.os.Handler;
+import android.os.CancellationSignal;
 import android.util.DisplayMetrics;
 import android.util.Log;
+import android.view.Display.ColorMode;
 import android.view.ScrollCaptureCallback;
 import android.view.ScrollCaptureSession;
 import android.view.Surface;
@@ -44,32 +48,42 @@
  * @param <V> the specific View subclass handled
  * @see ScrollCaptureViewHelper
  */
+@UiThread
 public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCallback {
 
-    public static final long NO_FRAME_PRODUCED = -1;
-
     private static final String TAG = "ScrollCaptureViewSupport";
 
     private static final boolean WAIT_FOR_ANIMATION = true;
 
     private final WeakReference<V> mWeakView;
     private final ScrollCaptureViewHelper<V> mViewHelper;
-    private ViewRenderer mRenderer;
-    private Handler mUiHandler;
+    private final ViewRenderer mRenderer;
     private boolean mStarted;
     private boolean mEnded;
 
     ScrollCaptureViewSupport(V containingView, ScrollCaptureViewHelper<V> viewHelper) {
         mWeakView = new WeakReference<>(containingView);
         mRenderer = new ViewRenderer();
-        mUiHandler = containingView.getHandler();
+        // TODO(b/177649144): provide access to color space from android.media.Image
         mViewHelper = viewHelper;
     }
 
-    // Base implementation of ScrollCaptureCallback
+    /** Based on ViewRootImpl#updateColorModeIfNeeded */
+    @ColorMode
+    private static int getColorMode(View containingView) {
+        Context context = containingView.getContext();
+        int colorMode = containingView.getViewRootImpl().mWindowAttributes.getColorMode();
+        if (!context.getResources().getConfiguration().isScreenWideColorGamut()) {
+            colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
+        }
+        return colorMode;
+    }
 
     @Override
-    public final void onScrollCaptureSearch(Consumer<Rect> onReady) {
+    public final void onScrollCaptureSearch(CancellationSignal signal, Consumer<Rect> onReady) {
+        if (signal.isCanceled()) {
+            return;
+        }
         V view = mWeakView.get();
         mStarted = false;
         mEnded = false;
@@ -82,7 +96,11 @@
     }
 
     @Override
-    public final void onScrollCaptureStart(ScrollCaptureSession session, Runnable onReady) {
+    public final void onScrollCaptureStart(ScrollCaptureSession session, CancellationSignal signal,
+            Runnable onReady) {
+        if (signal.isCanceled()) {
+            return;
+        }
         V view = mWeakView.get();
 
         mEnded = false;
@@ -99,18 +117,22 @@
     }
 
     @Override
-    public final void onScrollCaptureImageRequest(ScrollCaptureSession session, Rect requestRect) {
+    public final void onScrollCaptureImageRequest(ScrollCaptureSession session,
+            CancellationSignal signal, Rect requestRect, Consumer<Rect> onComplete) {
+        if (signal.isCanceled()) {
+            return;
+        }
         V view = mWeakView.get();
         if (view == null || !view.isVisibleToUser()) {
             // Signal to the controller that we have a problem and can't continue.
-            session.notifyBufferSent(NO_FRAME_PRODUCED, new Rect());
+            onComplete.accept(new Rect());
             return;
         }
         // Ask the view to scroll as needed to bring this area into view.
         ScrollResult scrollResult = mViewHelper.onScrollRequested(view, session.getScrollBounds(),
                 requestRect);
         if (scrollResult.availableArea.isEmpty()) {
-            session.notifyBufferSent(NO_FRAME_PRODUCED, scrollResult.availableArea);
+            onComplete.accept(scrollResult.availableArea);
             return;
         }
         view.invalidate(); // don't wait for vsync
@@ -121,17 +143,13 @@
         viewCaptureArea.offset(0, -scrollResult.scrollDelta);
 
         if (WAIT_FOR_ANIMATION) {
-            Log.d(TAG, "render: delaying until animation");
             view.postOnAnimation(() ->  {
-                Log.d(TAG, "postOnAnimation(): rendering now");
-                long resultFrame = mRenderer.renderView(view, viewCaptureArea);
-                Log.d(TAG, "notifyBufferSent: " + scrollResult.availableArea);
-
-                session.notifyBufferSent(resultFrame, new Rect(scrollResult.availableArea));
+                mRenderer.renderView(view, viewCaptureArea);
+                onComplete.accept(new Rect(scrollResult.availableArea));
             });
         } else {
-            long resultFrame = mRenderer.renderView(view, viewCaptureArea);
-            session.notifyBufferSent(resultFrame, new Rect(scrollResult.availableArea));
+            mRenderer.renderView(view, viewCaptureArea);
+            onComplete.accept(new Rect(scrollResult.availableArea));
         }
     }
 
@@ -239,7 +257,7 @@
             mCaptureRenderNode.endRecording();
         }
 
-        public long renderView(View view, Rect sourceRect) {
+        public void renderView(View view, Rect sourceRect) {
             if (updateForView(view)) {
                 setupLighting(view);
             }
@@ -258,7 +276,7 @@
             switch (request.syncAndDraw()) {
                 case HardwareRenderer.SYNC_OK:
                 case HardwareRenderer.SYNC_REDRAW_REQUESTED:
-                    return frameNumber;
+                    return;
 
                 case HardwareRenderer.SYNC_FRAME_DROPPED:
                     Log.e(TAG, "syncAndDraw(): SYNC_FRAME_DROPPED !");
@@ -270,7 +288,6 @@
                     Log.e(TAG, "syncAndDraw(): SYNC_CONTEXT_IS_STOPPED !");
                     break;
             }
-            return NO_FRAME_PRODUCED;
         }
 
         public void trimMemory() {
@@ -289,5 +306,17 @@
             mTempMatrix.mapRect(mTempRectF);
             mTempRectF.round(outRect);
         }
+
+        public void setColorMode(@ColorMode int colorMode) {
+            mRenderer.setColorMode(colorMode);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "ScrollCaptureViewSupport{"
+                + "view=" + mWeakView.get()
+                + ", helper=" + mViewHelper
+                + '}';
     }
 }
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 1b1e0bf..8ecc809 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -32,7 +32,6 @@
 import android.app.RemoteInputHistoryItem;
 import android.content.Context;
 import android.content.res.ColorStateList;
-import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.Typeface;
 import android.graphics.drawable.GradientDrawable;
@@ -62,11 +61,9 @@
 import android.widget.TextView;
 
 import com.android.internal.R;
-import com.android.internal.graphics.ColorUtils;
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Locale;
 import java.util.Objects;
 import java.util.function.Consumer;
 
@@ -118,7 +115,6 @@
     private ViewGroup mExpandButtonAndContentContainer;
     private NotificationExpandButton mExpandButton;
     private MessagingLinearLayout mImageMessageContainer;
-    private int mExpandButtonExpandedTopMargin;
     private int mBadgedSideMargins;
     private int mConversationAvatarSize;
     private int mConversationAvatarSizeExpanded;
@@ -147,7 +143,6 @@
     private int mFacePileProtectionWidth;
     private int mFacePileProtectionWidthExpanded;
     private boolean mImportantConversation;
-    private TextView mUnreadBadge;
     private View mFeedbackIcon;
     private float mMinTouchSize;
     private Icon mConversationIcon;
@@ -245,8 +240,6 @@
         mContentContainer = findViewById(R.id.notification_action_list_margin_target);
         mExpandButtonAndContentContainer = findViewById(R.id.expand_button_and_content_container);
         mExpandButton = findViewById(R.id.expand_button);
-        mExpandButtonExpandedTopMargin = getResources().getDimensionPixelSize(
-                R.dimen.conversation_expand_button_top_margin_expanded);
         mNotificationHeaderExpandedPadding = getResources().getDimensionPixelSize(
                 R.dimen.conversation_header_expanded_padding_end);
         mContentMarginEnd = getResources().getDimensionPixelSize(
@@ -286,7 +279,6 @@
         mAppName.setOnVisibilityChangedListener((visibility) -> {
             onAppNameVisibilityChanged();
         });
-        mUnreadBadge = findViewById(R.id.conversation_unread_count);
         mConversationContentStart = getResources().getDimensionPixelSize(
                 R.dimen.conversation_content_start);
         mInternalButtonPadding
@@ -426,17 +418,7 @@
 
     /** @hide */
     public void setUnreadCount(int unreadCount) {
-        boolean visible = mIsCollapsed && unreadCount > 1;
-        mUnreadBadge.setVisibility(visible ? VISIBLE : GONE);
-        if (visible) {
-            CharSequence text = unreadCount >= 100
-                    ? getResources().getString(R.string.unread_convo_overflow, 99)
-                    : String.format(Locale.getDefault(), "%d", unreadCount);
-            mUnreadBadge.setText(text);
-            mUnreadBadge.setBackgroundTintList(ColorStateList.valueOf(mLayoutColor));
-            boolean needDarkText = ColorUtils.calculateLuminance(mLayoutColor) > 0.5f;
-            mUnreadBadge.setTextColor(needDarkText ? Color.BLACK : Color.WHITE);
-        }
+        mExpandButton.setNumber(unreadCount);
     }
 
     private void addRemoteInputHistoryToMessages(
@@ -1132,15 +1114,16 @@
     }
 
     private void updateExpandButton() {
-        int gravity;
-        int topMargin = 0;
+        int buttonGravity;
+        int containerHeight;
         ViewGroup newContainer;
         if (mIsCollapsed) {
-            gravity = Gravity.CENTER;
+            buttonGravity = Gravity.CENTER;
+            containerHeight = ViewGroup.LayoutParams.WRAP_CONTENT;
             newContainer = mExpandButtonAndContentContainer;
         } else {
-            gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
-            topMargin = mExpandButtonExpandedTopMargin;
+            buttonGravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
+            containerHeight = ViewGroup.LayoutParams.MATCH_PARENT;
             newContainer = this;
         }
         mExpandButton.setExpanded(!mIsCollapsed);
@@ -1149,14 +1132,14 @@
         // content when collapsed, but allows the content to flow under it when expanded.
         if (newContainer != mExpandButtonContainer.getParent()) {
             ((ViewGroup) mExpandButtonContainer.getParent()).removeView(mExpandButtonContainer);
+            mExpandButtonContainer.getLayoutParams().height = containerHeight;
             newContainer.addView(mExpandButtonContainer);
         }
 
         // update if the expand button is centered
         LinearLayout.LayoutParams layoutParams =
                 (LinearLayout.LayoutParams) mExpandButton.getLayoutParams();
-        layoutParams.gravity = gravity;
-        layoutParams.topMargin = topMargin;
+        layoutParams.gravity = buttonGravity;
         mExpandButton.setLayoutParams(layoutParams);
     }
 
@@ -1210,6 +1193,7 @@
             mExpandButtonContainer.setVisibility(GONE);
             mConversationIconContainer.setOnClickListener(null);
         }
+        mExpandButton.setVisibility(VISIBLE);
         updateContentEndPaddings();
     }
 
diff --git a/core/java/com/android/internal/widget/NotificationExpandButton.java b/core/java/com/android/internal/widget/NotificationExpandButton.java
index 8add34f..fc4cc57 100644
--- a/core/java/com/android/internal/widget/NotificationExpandButton.java
+++ b/core/java/com/android/internal/widget/NotificationExpandButton.java
@@ -16,30 +16,42 @@
 
 package com.android.internal.widget;
 
-import static com.android.internal.widget.ColoredIconHelper.applyGrayTint;
-
+import android.annotation.ColorInt;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.RemotableViewMethod;
+import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.Button;
+import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.RemoteViews;
+import android.widget.TextView;
 
 import com.android.internal.R;
 
+import java.util.Locale;
+
 /**
  * An expand button in a notification
  */
 @RemoteViews.RemoteView
-public class NotificationExpandButton extends ImageView {
+public class NotificationExpandButton extends FrameLayout {
 
-    private final int mMinTouchTargetSize;
+    private View mPillView;
+    private TextView mNumberView;
+    private ImageView mIconView;
     private boolean mExpanded;
-    private int mOriginalNotificationColor;
+    private int mNumber;
+    private int mDefaultPillColor;
+    private int mDefaultTextColor;
+    private int mHighlightPillColor;
+    private int mHighlightTextColor;
+    private boolean mDisallowColor;
 
     public NotificationExpandButton(Context context) {
         this(context, null, 0, 0);
@@ -57,7 +69,14 @@
     public NotificationExpandButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        mMinTouchTargetSize = (int) (getResources().getDisplayMetrics().density * 48 + 0.5);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mPillView = findViewById(R.id.expand_button_pill);
+        mNumberView = findViewById(R.id.expand_button_number);
+        mIconView = findViewById(R.id.expand_button_icon);
     }
 
     /**
@@ -72,7 +91,6 @@
         } else {
             super.getBoundsOnScreen(outRect, clipToParent);
         }
-        extendRectToMinTouchSize(outRect);
     }
 
     /**
@@ -89,32 +107,12 @@
         return super.pointInView(localX, localY, slop);
     }
 
-    @RemotableViewMethod
-    public void setOriginalNotificationColor(int color) {
-        mOriginalNotificationColor = color;
-    }
-
-    public int getOriginalNotificationColor() {
-        return mOriginalNotificationColor;
-    }
-
     /**
-     * Set the button's color filter: to gray if true, otherwise colored.
-     * If this button has no original color, this has no effect.
+     * Disable the use of the accent colors for this view, if true.
      */
     public void setGrayedOut(boolean shouldApply) {
-        applyGrayTint(mContext, getDrawable(), shouldApply, mOriginalNotificationColor);
-    }
-
-    private void extendRectToMinTouchSize(Rect rect) {
-        if (rect.width() < mMinTouchTargetSize) {
-            rect.left = rect.centerX() - mMinTouchTargetSize / 2;
-            rect.right = rect.left + mMinTouchTargetSize;
-        }
-        if (rect.height() < mMinTouchTargetSize) {
-            rect.top = rect.centerY() - mMinTouchTargetSize / 2;
-            rect.bottom = rect.top + mMinTouchTargetSize;
-        }
+        mDisallowColor = shouldApply;
+        updateColors();
     }
 
     @Override
@@ -129,10 +127,10 @@
     @RemotableViewMethod
     public void setExpanded(boolean expanded) {
         mExpanded = expanded;
-        updateExpandButton();
+        updateExpandedState();
     }
 
-    private void updateExpandButton() {
+    private void updateExpandedState() {
         int drawableId;
         int contentDescriptionId;
         if (mExpanded) {
@@ -142,8 +140,89 @@
             drawableId = R.drawable.ic_expand_notification;
             contentDescriptionId = R.string.expand_button_content_description_collapsed;
         }
-        setImageDrawable(getContext().getDrawable(drawableId));
-        setColorFilter(mOriginalNotificationColor);
         setContentDescription(mContext.getText(contentDescriptionId));
+        mIconView.setImageDrawable(getContext().getDrawable(drawableId));
+
+        // changing the expanded state can affect the number display
+        updateNumber();
+    }
+
+    private void updateNumber() {
+        if (shouldShowNumber()) {
+            CharSequence text = mNumber >= 100
+                    ? getResources().getString(R.string.unread_convo_overflow, 99)
+                    : String.format(Locale.getDefault(), "%d", mNumber);
+            mNumberView.setText(text);
+            mNumberView.setVisibility(VISIBLE);
+        } else {
+            mNumberView.setVisibility(GONE);
+        }
+
+        // changing number can affect the color
+        updateColors();
+    }
+
+    private void updateColors() {
+        if (shouldShowNumber() && !mDisallowColor) {
+            mPillView.setBackgroundTintList(ColorStateList.valueOf(mHighlightPillColor));
+            mIconView.setColorFilter(mHighlightTextColor);
+            mNumberView.setTextColor(mHighlightTextColor);
+        } else {
+            mPillView.setBackgroundTintList(ColorStateList.valueOf(mDefaultPillColor));
+            mIconView.setColorFilter(mDefaultTextColor);
+            mNumberView.setTextColor(mDefaultTextColor);
+        }
+    }
+
+    private boolean shouldShowNumber() {
+        return !mExpanded && mNumber > 1;
+    }
+
+    /**
+     * Set the color used for the expand chevron and the text
+     */
+    @RemotableViewMethod
+    public void setDefaultTextColor(int color) {
+        mDefaultTextColor = color;
+        updateColors();
+    }
+
+    /**
+     * Sets the color used to for the expander when there is no number shown
+     */
+    @RemotableViewMethod
+    public void setDefaultPillColor(@ColorInt int color) {
+        mDefaultPillColor = color;
+        updateColors();
+    }
+
+    /**
+     * Set the color used for the expand chevron and the text
+     */
+    @RemotableViewMethod
+    public void setHighlightTextColor(int color) {
+        mHighlightTextColor = color;
+        updateColors();
+    }
+
+    /**
+     * Sets the color used to highlight the expander when there is a number shown
+     */
+    @RemotableViewMethod
+    public void setHighlightPillColor(@ColorInt int color) {
+        mHighlightPillColor = color;
+        updateColors();
+    }
+
+    /**
+     * Sets the number shown inside the expand button.
+     * This only appears when the expand button is collapsed, and when greater than 1.
+     */
+    @RemotableViewMethod
+    public void setNumber(int number) {
+        if (mNumber != number) {
+            mNumber = number;
+            updateNumber();
+        }
     }
 }
diff --git a/core/java/com/android/internal/widget/NotificationVanishingFrameLayout.java b/core/java/com/android/internal/widget/NotificationVanishingFrameLayout.java
new file mode 100644
index 0000000..742bdfd
--- /dev/null
+++ b/core/java/com/android/internal/widget/NotificationVanishingFrameLayout.java
@@ -0,0 +1,70 @@
+/*
+ * 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.widget;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.RemoteViews;
+
+/**
+ * This view will measure itself as having 0 size if all of its children are {@link #GONE}.
+ * Otherwise it acts like a normal {@link FrameLayout}.
+ */
+@RemoteViews.RemoteView
+public class NotificationVanishingFrameLayout extends FrameLayout {
+    public NotificationVanishingFrameLayout(Context context) {
+        this(context, null, 0, 0);
+    }
+
+    public NotificationVanishingFrameLayout(Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, 0, 0);
+    }
+
+    public NotificationVanishingFrameLayout(Context context, @Nullable AttributeSet attrs,
+            int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public NotificationVanishingFrameLayout(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        if (allChildrenGone()) {
+            int zeroSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY);
+            super.onMeasure(zeroSpec, zeroSpec);
+        } else {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        }
+    }
+
+    private boolean allChildrenGone() {
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child =  getChildAt(i);
+            if (child != null && child.getVisibility() != GONE) {
+                return false;
+            }
+        }
+        return true;
+    }
+}
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 143017c..fd6038f 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -36,7 +36,6 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.MotionEvent.PointerCoords;
-import android.view.Surface;
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewConfiguration;
@@ -60,9 +59,6 @@
      */
     private static final String GESTURE_EXCLUSION_PROP = "debug.pointerlocation.showexclusion";
 
-    private static final boolean ENABLE_PER_WINDOW_INPUT_ROTATION =
-            SystemProperties.getBoolean("persist.debug.per_window_input_rotation", false);
-
     public static class PointerState {
         // Trace of previous points.
         private float[] mTraceX = new float[32];
@@ -356,21 +352,6 @@
                     .toString(), 1 + itemW * 6, base, mTextPaint);
         }
 
-        int saveId = canvas.save();
-        if (ENABLE_PER_WINDOW_INPUT_ROTATION) {
-            // Rotate negative (since we're rotating the drawing canvas vs the output).
-            canvas.rotate(-90.0f * mContext.getDisplay().getRotation());
-            switch (mContext.getDisplay().getRotation()) {
-                case Surface.ROTATION_90:
-                    canvas.translate(-canvas.getHeight(), 0);
-                    break;
-                case Surface.ROTATION_180:
-                    canvas.translate(-canvas.getWidth(), -canvas.getHeight());
-                    break;
-                case Surface.ROTATION_270:
-                    canvas.translate(0, -canvas.getWidth());
-            }
-        }
         // Pointer trace.
         for (int p = 0; p < NP; p++) {
             final PointerState ps = mPointers.get(p);
@@ -480,7 +461,6 @@
                 }
             }
         }
-        canvas.restoreToCount(saveId);
     }
 
     private void logMotionEvent(String type, MotionEvent event) {
diff --git a/core/java/com/android/server/OWNERS b/core/java/com/android/server/OWNERS
new file mode 100644
index 0000000..12629254
--- /dev/null
+++ b/core/java/com/android/server/OWNERS
@@ -0,0 +1 @@
+per-file SystemConfig.java = toddke@google.com
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 8982519..bac6bbe 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -24,6 +24,7 @@
 import android.content.ComponentName;
 import android.content.pm.FeatureInfo;
 import android.content.pm.PackageManager;
+import android.hardware.SensorPrivacyManager;
 import android.os.Build;
 import android.os.CarrierAssociatedAppEntry;
 import android.os.Environment;
@@ -94,9 +95,6 @@
     // property for runtime configuration differentiation in vendor
     private static final String VENDOR_SKU_PROPERTY = "ro.boot.product.vendor.sku";
 
-    // property for background blur support in surface flinger
-    private static final String BLUR_PROPERTY = "ro.surface_flinger.supports_background_blur";
-
     // Group-ids that are given to all packages as read from etc/permissions/*.xml.
     int[] mGlobalGids = EmptyArray.INT;
 
@@ -1234,10 +1232,9 @@
             addFeature(PackageManager.FEATURE_RAM_NORMAL, 0);
         }
 
-        if (IncrementalManager.isFeatureEnabled()) {
-            addFeature(PackageManager.FEATURE_INCREMENTAL_DELIVERY, 0);
-            addFeature(PackageManager.FEATURE_INCREMENTAL_DELIVERY_VERSION,
-                    IncrementalManager.isV2Available() ? 2 : 1);
+        final int incrementalVersion = IncrementalManager.getVersion();
+        if (incrementalVersion > 0) {
+            addFeature(PackageManager.FEATURE_INCREMENTAL_DELIVERY, incrementalVersion);
         }
 
         if (PackageManager.APP_ENUMERATION_ENABLED_BY_DEFAULT) {
@@ -1248,8 +1245,12 @@
             addFeature(PackageManager.FEATURE_IPSEC_TUNNELS, 0);
         }
 
-        if (SystemProperties.get(BLUR_PROPERTY, "default").equals("1")) {
-            addFeature(PackageManager.FEATURE_CROSS_LAYER_BLUR, 0);
+        if (SensorPrivacyManager.USE_MICROPHONE_TOGGLE) {
+            addFeature(PackageManager.FEATURE_MICROPHONE_TOGGLE, 0);
+        }
+
+        if (SensorPrivacyManager.USE_CAMERA_TOGGLE) {
+            addFeature(PackageManager.FEATURE_CAMERA_TOGGLE, 0);
         }
 
         for (String featureName : mUnavailableFeatures) {
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index dd1a594..d6d3387 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -51,6 +51,7 @@
         "android_util_XmlBlock.cpp",
         "android_util_jar_StrictJarFile.cpp",
         "com_android_internal_util_VirtualRefBasePtr.cpp",
+        ":deviceproductinfoconstants_aidl",
     ],
 
     include_dirs: [
@@ -121,6 +122,7 @@
                 "android_view_PointerIcon.cpp",
                 "android_view_Surface.cpp",
                 "android_view_SurfaceControl.cpp",
+                "android_view_SurfaceControlFpsListener.cpp",
                 "android_graphics_BLASTBufferQueue.cpp",
                 "android_view_SurfaceSession.cpp",
                 "android_view_TextureView.cpp",
@@ -149,7 +151,7 @@
                 "android_os_VintfRuntimeInfo.cpp",
                 "android_os_incremental_IncrementalManager.cpp",
                 "android_net_LocalSocketImpl.cpp",
-                "android_net_NetUtils.cpp",
+                "android_net_NetworkUtils.cpp",
                 "android_service_DataLoaderService.cpp",
                 "android_util_AssetManager.cpp",
                 "android_util_Binder.cpp",
@@ -210,6 +212,7 @@
                 "com_android_internal_os_KernelSingleProcessCpuThreadReader.cpp",
                 "com_android_internal_os_KernelSingleUidTimeReader.cpp",
                 "com_android_internal_os_Zygote.cpp",
+                "com_android_internal_os_ZygoteCommandBuffer.cpp",
                 "com_android_internal_os_ZygoteInit.cpp",
                 "hwbinder/EphemeralStorage.cpp",
                 "fd_utils.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 1751be0..ddd8613 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -120,6 +120,7 @@
 extern int register_android_view_InputWindowHandle(JNIEnv* env);
 extern int register_android_view_Surface(JNIEnv* env);
 extern int register_android_view_SurfaceControl(JNIEnv* env);
+extern int register_android_view_SurfaceControlFpsListener(JNIEnv* env);
 extern int register_android_view_SurfaceSession(JNIEnv* env);
 extern int register_android_view_CompositionSamplingListener(JNIEnv* env);
 extern int register_android_view_TextureView(JNIEnv* env);
@@ -197,6 +198,7 @@
 extern int register_com_android_internal_os_KernelSingleProcessCpuThreadReader(JNIEnv* env);
 extern int register_com_android_internal_os_KernelSingleUidTimeReader(JNIEnv *env);
 extern int register_com_android_internal_os_Zygote(JNIEnv *env);
+extern int register_com_android_internal_os_ZygoteCommandBuffer(JNIEnv *env);
 extern int register_com_android_internal_os_ZygoteInit(JNIEnv *env);
 extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
 
@@ -1488,6 +1490,7 @@
         REG_JNI(register_android_view_InputWindowHandle),
         REG_JNI(register_android_view_Surface),
         REG_JNI(register_android_view_SurfaceControl),
+        REG_JNI(register_android_view_SurfaceControlFpsListener),
         REG_JNI(register_android_view_SurfaceSession),
         REG_JNI(register_android_view_CompositionSamplingListener),
         REG_JNI(register_android_view_TextureView),
@@ -1529,6 +1532,7 @@
         REG_JNI(register_com_android_internal_net_NetworkUtilsInternal),
         REG_JNI(register_com_android_internal_os_ClassLoaderFactory),
         REG_JNI(register_com_android_internal_os_Zygote),
+        REG_JNI(register_com_android_internal_os_ZygoteCommandBuffer),
         REG_JNI(register_com_android_internal_os_ZygoteInit),
         REG_JNI(register_com_android_internal_util_VirtualRefBasePtr),
         REG_JNI(register_android_hardware_Camera),
diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp
index c7439f1..b0c5751 100644
--- a/core/jni/android_content_res_ApkAssets.cpp
+++ b/core/jni/android_content_res_ApkAssets.cpp
@@ -83,6 +83,10 @@
     return true;
   }
 
+  std::optional<std::string_view> GetPath() const override {
+    return {};
+  }
+
   const std::string& GetDebugName() const override {
     return debug_name_;
   }
@@ -358,8 +362,16 @@
 }
 
 static jstring NativeGetAssetPath(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
-  const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
-  return env->NewStringUTF(apk_assets->GetPath().c_str());
+  auto apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
+  if (auto path = apk_assets->GetPath()) {
+    return env->NewStringUTF(path->data());
+  }
+  return nullptr;
+}
+
+static jstring NativeGetDebugName(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
+  auto apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
+  return env->NewStringUTF(apk_assets->GetDebugName().c_str());
 }
 
 static jlong NativeGetStringBlock(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
@@ -467,6 +479,7 @@
      (void*)NativeLoadFromFdOffset},
     {"nativeGetFinalizer", "()J", (void*)NativeGetFinalizer},
     {"nativeGetAssetPath", "(J)Ljava/lang/String;", (void*)NativeGetAssetPath},
+    {"nativeGetDebugName", "(J)Ljava/lang/String;", (void*)NativeGetDebugName},
     {"nativeGetStringBlock", "(J)J", (void*)NativeGetStringBlock},
     {"nativeIsUpToDate", "(J)Z", (void*)NativeIsUpToDate},
     {"nativeOpenXml", "(JLjava/lang/String;)J", (void*)NativeOpenXml},
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 8d193bf..0e0f98e 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -861,6 +861,23 @@
     return jStatus;
 }
 
+static void android_media_AudioRecord_setLogSessionId(JNIEnv *env, jobject thiz,
+                                                      jstring jlogSessionId) {
+    sp<AudioRecord> record = getAudioRecord(env, thiz);
+    if (record == nullptr) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Unable to retrieve AudioRecord pointer for setLogSessionId()");
+    }
+    if (jlogSessionId == nullptr) {
+        ALOGV("%s: logSessionId nullptr", __func__);
+        record->setLogSessionId(nullptr);
+        return;
+    }
+    ScopedUtfChars logSessionId(env, jlogSessionId);
+    ALOGV("%s: logSessionId '%s'", __func__, logSessionId.c_str());
+    record->setLogSessionId(logSessionId.c_str());
+}
+
 // ----------------------------------------------------------------------------
 static jint android_media_AudioRecord_get_port_id(JNIEnv *env,  jobject thiz) {
     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
@@ -876,50 +893,48 @@
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 static const JNINativeMethod gMethods[] = {
-    // name,               signature,  funcPtr
-    {"native_start",         "(II)I",    (void *)android_media_AudioRecord_start},
-    {"native_stop",          "()V",    (void *)android_media_AudioRecord_stop},
-    {"native_setup",         "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILjava/lang/String;J)I",
-                                      (void *)android_media_AudioRecord_setup},
-    {"native_finalize",      "()V",    (void *)android_media_AudioRecord_finalize},
-    {"native_release",       "()V",    (void *)android_media_AudioRecord_release},
-    {"native_read_in_byte_array",
-                             "([BIIZ)I",
-                                     (void *)android_media_AudioRecord_readInArray<jbyteArray>},
-    {"native_read_in_short_array",
-                             "([SIIZ)I",
-                                     (void *)android_media_AudioRecord_readInArray<jshortArray>},
-    {"native_read_in_float_array",
-                             "([FIIZ)I",
-                                     (void *)android_media_AudioRecord_readInArray<jfloatArray>},
-    {"native_read_in_direct_buffer","(Ljava/lang/Object;IZ)I",
-                                       (void *)android_media_AudioRecord_readInDirectBuffer},
-    {"native_get_buffer_size_in_frames",
-                             "()I", (void *)android_media_AudioRecord_get_buffer_size_in_frames},
-    {"native_set_marker_pos","(I)I",   (void *)android_media_AudioRecord_set_marker_pos},
-    {"native_get_marker_pos","()I",    (void *)android_media_AudioRecord_get_marker_pos},
-    {"native_set_pos_update_period",
-                             "(I)I",   (void *)android_media_AudioRecord_set_pos_update_period},
-    {"native_get_pos_update_period",
-                             "()I",    (void *)android_media_AudioRecord_get_pos_update_period},
-    {"native_get_min_buff_size",
-                             "(III)I",   (void *)android_media_AudioRecord_get_min_buff_size},
-    {"native_getMetrics",    "()Landroid/os/PersistableBundle;",
-                                         (void *)android_media_AudioRecord_native_getMetrics},
-    {"native_setInputDevice", "(I)Z", (void *)android_media_AudioRecord_setInputDevice},
-    {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioRecord_getRoutedDeviceId},
-    {"native_enableDeviceCallback", "()V", (void *)android_media_AudioRecord_enableDeviceCallback},
-    {"native_disableDeviceCallback", "()V",
-                                        (void *)android_media_AudioRecord_disableDeviceCallback},
-    {"native_get_timestamp", "(Landroid/media/AudioTimestamp;I)I",
-                                       (void *)android_media_AudioRecord_get_timestamp},
-    {"native_get_active_microphones", "(Ljava/util/ArrayList;)I",
-                                        (void *)android_media_AudioRecord_get_active_microphones},
-    {"native_getPortId", "()I", (void *)android_media_AudioRecord_get_port_id},
-    {"native_set_preferred_microphone_direction", "(I)I",
-                        (void *)android_media_AudioRecord_set_preferred_microphone_direction},
-    {"native_set_preferred_microphone_field_dimension", "(F)I",
-                        (void *)android_media_AudioRecord_set_preferred_microphone_field_dimension},
+        {"native_start", "(II)I", (void *)android_media_AudioRecord_start},
+        {"native_stop", "()V", (void *)android_media_AudioRecord_stop},
+        {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILjava/lang/String;J)I",
+         (void *)android_media_AudioRecord_setup},
+        {"native_finalize", "()V", (void *)android_media_AudioRecord_finalize},
+        {"native_release", "()V", (void *)android_media_AudioRecord_release},
+        {"native_read_in_byte_array", "([BIIZ)I",
+         (void *)android_media_AudioRecord_readInArray<jbyteArray>},
+        {"native_read_in_short_array", "([SIIZ)I",
+         (void *)android_media_AudioRecord_readInArray<jshortArray>},
+        {"native_read_in_float_array", "([FIIZ)I",
+         (void *)android_media_AudioRecord_readInArray<jfloatArray>},
+        {"native_read_in_direct_buffer", "(Ljava/lang/Object;IZ)I",
+         (void *)android_media_AudioRecord_readInDirectBuffer},
+        {"native_get_buffer_size_in_frames", "()I",
+         (void *)android_media_AudioRecord_get_buffer_size_in_frames},
+        {"native_set_marker_pos", "(I)I", (void *)android_media_AudioRecord_set_marker_pos},
+        {"native_get_marker_pos", "()I", (void *)android_media_AudioRecord_get_marker_pos},
+        {"native_set_pos_update_period", "(I)I",
+         (void *)android_media_AudioRecord_set_pos_update_period},
+        {"native_get_pos_update_period", "()I",
+         (void *)android_media_AudioRecord_get_pos_update_period},
+        {"native_get_min_buff_size", "(III)I", (void *)android_media_AudioRecord_get_min_buff_size},
+        {"native_getMetrics", "()Landroid/os/PersistableBundle;",
+         (void *)android_media_AudioRecord_native_getMetrics},
+        {"native_setInputDevice", "(I)Z", (void *)android_media_AudioRecord_setInputDevice},
+        {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioRecord_getRoutedDeviceId},
+        {"native_enableDeviceCallback", "()V",
+         (void *)android_media_AudioRecord_enableDeviceCallback},
+        {"native_disableDeviceCallback", "()V",
+         (void *)android_media_AudioRecord_disableDeviceCallback},
+        {"native_get_timestamp", "(Landroid/media/AudioTimestamp;I)I",
+         (void *)android_media_AudioRecord_get_timestamp},
+        {"native_get_active_microphones", "(Ljava/util/ArrayList;)I",
+         (void *)android_media_AudioRecord_get_active_microphones},
+        {"native_getPortId", "()I", (void *)android_media_AudioRecord_get_port_id},
+        {"native_set_preferred_microphone_direction", "(I)I",
+         (void *)android_media_AudioRecord_set_preferred_microphone_direction},
+        {"native_set_preferred_microphone_field_dimension", "(F)I",
+         (void *)android_media_AudioRecord_set_preferred_microphone_field_dimension},
+        {"native_setLogSessionId", "(Ljava/lang/String;)V",
+         (void *)android_media_AudioRecord_setLogSessionId},
 };
 
 // field names found in android/media/AudioRecord.java
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index da60a75..cae6db5 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -1426,8 +1426,13 @@
         jniThrowException(env, "java/lang/IllegalStateException",
                           "Unable to retrieve AudioTrack pointer for setLogSessionId()");
     }
+    if (jlogSessionId == nullptr) {
+        ALOGV("%s: logSessionId nullptr", __func__);
+        track->setLogSessionId(nullptr);
+        return;
+    }
     ScopedUtfChars logSessionId(env, jlogSessionId);
-    ALOGV("%s: logSessionId %s", __func__, logSessionId.c_str());
+    ALOGV("%s: logSessionId '%s'", __func__, logSessionId.c_str());
     track->setLogSessionId(logSessionId.c_str());
 }
 
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetworkUtils.cpp
similarity index 94%
rename from core/jni/android_net_NetUtils.cpp
rename to core/jni/android_net_NetworkUtils.cpp
index e2af87e..7508108 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetworkUtils.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "NetUtils"
+#define LOG_TAG "NetworkUtils"
 
 #include <vector>
 
@@ -123,15 +123,6 @@
     return setNetworkForSocket(netId, AFileDescriptor_getFD(env, javaFd));
 }
 
-static jboolean android_net_utils_protectFromVpn(JNIEnv *env, jobject thiz, jint socket)
-{
-    return (jboolean) !protectFromVpn(socket);
-}
-
-static jboolean android_net_utils_protectFromVpnWithFd(JNIEnv *env, jobject thiz, jobject javaFd) {
-    return android_net_utils_protectFromVpn(env, thiz, AFileDescriptor_getFD(env, javaFd));
-}
-
 static jboolean android_net_utils_queryUserAccess(JNIEnv *env, jobject thiz, jint uid, jint netId)
 {
     return (jboolean) !queryUserAccess(uid, netId);
@@ -276,8 +267,6 @@
     { "getBoundNetworkForProcess", "()I", (void*) android_net_utils_getBoundNetworkForProcess },
     { "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
     { "bindSocketToNetwork", "(Ljava/io/FileDescriptor;I)I", (void*) android_net_utils_bindSocketToNetwork },
-    { "protectFromVpn", "(I)Z", (void*) android_net_utils_protectFromVpn },
-    { "protectFromVpn", "(Ljava/io/FileDescriptor;)Z", (void*) android_net_utils_protectFromVpnWithFd },
     { "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess },
     { "attachDropAllBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDropAllBPFFilter },
     { "detachBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_detachBPFFilter },
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 451ea93..cbf4481 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -27,6 +27,7 @@
 #include <android-base/chrono_utils.h>
 #include <android/graphics/region.h>
 #include <android/gui/BnScreenCaptureListener.h>
+#include <android/hardware/display/IDeviceProductInfoConstants.h>
 #include <android/os/IInputConstants.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_hardware_HardwareBuffer.h>
@@ -1022,16 +1023,24 @@
     } else {
         LOG_FATAL("Unknown alternative for variant DeviceProductInfo::ManufactureOrModelDate");
     }
-    auto relativeAddress = env->NewIntArray(info->relativeAddress.size());
-    auto relativeAddressData = env->GetIntArrayElements(relativeAddress, nullptr);
-    for (int i = 0; i < info->relativeAddress.size(); i++) {
-        relativeAddressData[i] = info->relativeAddress[i];
+    jint connectionToSinkType;
+    // Relative address maps to HDMI physical address. All addresses are 4 digits long allowing
+    // for a 5–device-deep hierarchy. For more information, refer:
+    // Section 8.7 - Physical Address of HDMI Specification Version 1.3a
+    using android::hardware::display::IDeviceProductInfoConstants;
+    if (info->relativeAddress.size() != 4) {
+        connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_UNKNOWN;
+    } else if (info->relativeAddress[0] == 0) {
+        connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_BUILT_IN;
+    } else if (info->relativeAddress[1] == 0) {
+        connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_DIRECT;
+    } else {
+        connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_TRANSITIVE;
     }
-    env->ReleaseIntArrayElements(relativeAddress, relativeAddressData, 0);
 
     return env->NewObject(gDeviceProductInfoClassInfo.clazz, gDeviceProductInfoClassInfo.ctor, name,
                           manufacturerPnpId, productId, modelYear, manufactureDate,
-                          relativeAddress);
+                          connectionToSinkType);
 }
 
 static jobject nativeGetStaticDisplayInfo(JNIEnv* env, jclass clazz, jobject tokenObj) {
@@ -1970,7 +1979,7 @@
                              "Ljava/lang/String;"
                              "Ljava/lang/Integer;"
                              "Landroid/hardware/display/DeviceProductInfo$ManufactureDate;"
-                             "[I)V");
+                             "I)V");
 
     jclass deviceProductInfoManufactureDateClazz =
             FindClassOrDie(env, "android/hardware/display/DeviceProductInfo$ManufactureDate");
diff --git a/core/jni/android_view_SurfaceControlFpsListener.cpp b/core/jni/android_view_SurfaceControlFpsListener.cpp
new file mode 100644
index 0000000..6fa12e5
--- /dev/null
+++ b/core/jni/android_view_SurfaceControlFpsListener.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SurfaceControlFpsListener"
+
+#include <android/gui/BnFpsListener.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <nativehelper/JNIHelp.h>
+#include <utils/Log.h>
+#include <utils/RefBase.h>
+
+#include "android_util_Binder.h"
+#include "core_jni_helpers.h"
+
+namespace android {
+
+namespace {
+
+struct {
+    jclass mClass;
+    jmethodID mDispatchOnFpsReported;
+} gListenerClassInfo;
+
+struct SurfaceControlFpsListener : public gui::BnFpsListener {
+    SurfaceControlFpsListener(JNIEnv* env, jobject listener)
+          : mListener(env->NewWeakGlobalRef(listener)) {}
+
+    binder::Status onFpsReported(float fps) override {
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+        LOG_ALWAYS_FATAL_IF(env == nullptr, "Unable to retrieve JNIEnv in onFpsReported.");
+
+        jobject listener = env->NewGlobalRef(mListener);
+        if (listener == NULL) {
+            // Weak reference went out of scope
+            return binder::Status::ok();
+        }
+        env->CallStaticVoidMethod(gListenerClassInfo.mClass,
+                                  gListenerClassInfo.mDispatchOnFpsReported, listener,
+                                  static_cast<jfloat>(fps));
+        env->DeleteGlobalRef(listener);
+
+        if (env->ExceptionCheck()) {
+            ALOGE("SurfaceControlFpsListener.onFpsReported() failed.");
+            LOGE_EX(env);
+            env->ExceptionClear();
+        }
+        return binder::Status::ok();
+    }
+
+protected:
+    virtual ~SurfaceControlFpsListener() {
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+        env->DeleteWeakGlobalRef(mListener);
+    }
+
+private:
+    jweak mListener;
+};
+
+jlong nativeCreate(JNIEnv* env, jclass clazz, jobject obj) {
+    SurfaceControlFpsListener* listener = new SurfaceControlFpsListener(env, obj);
+    listener->incStrong((void*)nativeCreate);
+    return reinterpret_cast<jlong>(listener);
+}
+
+void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
+    SurfaceControlFpsListener* listener = reinterpret_cast<SurfaceControlFpsListener*>(ptr);
+    listener->decStrong((void*)nativeCreate);
+}
+
+void nativeRegister(JNIEnv* env, jclass clazz, jlong ptr, jlong layerObj) {
+    sp<SurfaceControlFpsListener> listener = reinterpret_cast<SurfaceControlFpsListener*>(ptr);
+    auto layer = reinterpret_cast<SurfaceControl*>(layerObj);
+    sp<IBinder> layerHandle = layer != nullptr ? layer->getHandle() : nullptr;
+    if (SurfaceComposerClient::addFpsListener(layerHandle, listener) != OK) {
+        constexpr auto error_msg = "Couldn't addFpsListener";
+        ALOGE(error_msg);
+        jniThrowRuntimeException(env, error_msg);
+    }
+}
+
+void nativeUnregister(JNIEnv* env, jclass clazz, jlong ptr) {
+    sp<SurfaceControlFpsListener> listener = reinterpret_cast<SurfaceControlFpsListener*>(ptr);
+
+    if (SurfaceComposerClient::removeFpsListener(listener) != OK) {
+        constexpr auto error_msg = "Couldn't removeFpsListener";
+        ALOGE(error_msg);
+        jniThrowRuntimeException(env, error_msg);
+    }
+}
+
+const JNINativeMethod gMethods[] = {
+        /* name, signature, funcPtr */
+        {"nativeCreate", "(Landroid/view/SurfaceControlFpsListener;)J", (void*)nativeCreate},
+        {"nativeDestroy", "(J)V", (void*)nativeDestroy},
+        {"nativeRegister", "(JJ)V", (void*)nativeRegister},
+        {"nativeUnregister", "(J)V", (void*)nativeUnregister}};
+
+} // namespace
+
+int register_android_view_SurfaceControlFpsListener(JNIEnv* env) {
+    int res = jniRegisterNativeMethods(env, "android/view/SurfaceControlFpsListener", gMethods,
+                                       NELEM(gMethods));
+    LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
+
+    jclass clazz = env->FindClass("android/view/SurfaceControlFpsListener");
+    gListenerClassInfo.mClass = MakeGlobalRefOrDie(env, clazz);
+    gListenerClassInfo.mDispatchOnFpsReported =
+            env->GetStaticMethodID(clazz, "dispatchOnFpsReported",
+                                   "(Landroid/view/SurfaceControlFpsListener;F)V");
+    return 0;
+}
+
+} // namespace android
diff --git a/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp b/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp
index 10fc18d..980e12d 100644
--- a/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp
+++ b/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <android/file_descriptor_jni.h>
+
 #include "NetdClient.h"
 #include "core_jni_helpers.h"
 #include "jni.h"
@@ -24,9 +26,20 @@
     setAllowNetworkingForProcess(hasConnectivity == JNI_TRUE);
 }
 
+static jboolean android_net_utils_protectFromVpn(JNIEnv *env, jobject thiz, jint socket) {
+    return (jboolean)!protectFromVpn(socket);
+}
+
+static jboolean android_net_utils_protectFromVpnWithFd(JNIEnv *env, jobject thiz, jobject javaFd) {
+    return android_net_utils_protectFromVpn(env, thiz, AFileDescriptor_getFD(env, javaFd));
+}
+
 static const JNINativeMethod gNetworkUtilMethods[] = {
         {"setAllowNetworkingForProcess", "(Z)V",
          (void *)android_net_utils_setAllowNetworkingForProcess},
+        {"protectFromVpn", "(I)Z", (void *)android_net_utils_protectFromVpn},
+        {"protectFromVpn", "(Ljava/io/FileDescriptor;)Z",
+         (void *)android_net_utils_protectFromVpnWithFd},
 };
 
 int register_com_android_internal_net_NetworkUtilsInternal(JNIEnv *env) {
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index e801725..bcfb06b 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -17,6 +17,8 @@
 #define LOG_TAG "Zygote"
 #define ATRACE_TAG ATRACE_TAG_DALVIK
 
+#include "com_android_internal_os_Zygote.h"
+
 #include <async_safe/log.h>
 
 // sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc
@@ -91,19 +93,6 @@
 
 #include "nativebridge/native_bridge.h"
 
-/* Functions in the callchain during the fork shall not be protected with
-   Armv8.3-A Pointer Authentication, otherwise child will not be able to return. */
-#ifdef __ARM_FEATURE_PAC_DEFAULT
-#ifdef __ARM_FEATURE_BTI_DEFAULT
-#define NO_PAC_FUNC __attribute__((target("branch-protection=bti")))
-#else
-#define NO_PAC_FUNC __attribute__((target("branch-protection=none")))
-#endif /* __ARM_FEATURE_BTI_DEFAULT */
-#else /* !__ARM_FEATURE_PAC_DEFAULT */
-#define NO_PAC_FUNC
-#endif /* __ARM_FEATURE_PAC_DEFAULT */
-
-
 namespace {
 
 // TODO (chriswailes): Add a function to initialize native Zygote data.
@@ -118,8 +107,7 @@
 using android::base::WriteStringToFile;
 using android::base::GetBoolProperty;
 
-#define CREATE_ERROR(...) StringPrintf("%s:%d: ", __FILE__, __LINE__). \
-                              append(StringPrintf(__VA_ARGS__))
+using android::zygote::ZygoteFailure;
 
 // This type is duplicated in fd_utils.h
 typedef const std::function<void(std::string)>& fail_fn_t;
@@ -214,7 +202,7 @@
   static constexpr EntryStorage INVALID_ENTRY_VALUE = {-1, -1};
 
   std::atomic<EntryStorage> mStorage;
-  static_assert(decltype(mStorage)::is_always_lock_free);
+  static_assert(decltype(mStorage)::is_always_lock_free);  // Accessed from signal handler.
 
  public:
   constexpr UsapTableEntry() : mStorage(INVALID_ENTRY_VALUE) {}
@@ -316,15 +304,14 @@
 static FileDescriptorTable* gOpenFdTable = nullptr;
 
 // Must match values in com.android.internal.os.Zygote.
-// Note that there are gaps in the constants:
-// This is to further keep the values consistent with IVold.aidl
+// The values should be consistent with IVold.aidl
 enum MountExternalKind {
     MOUNT_EXTERNAL_NONE = 0,
     MOUNT_EXTERNAL_DEFAULT = 1,
-    MOUNT_EXTERNAL_INSTALLER = 5,
-    MOUNT_EXTERNAL_PASS_THROUGH = 7,
-    MOUNT_EXTERNAL_ANDROID_WRITABLE = 8,
-    MOUNT_EXTERNAL_COUNT = 9
+    MOUNT_EXTERNAL_INSTALLER = 2,
+    MOUNT_EXTERNAL_PASS_THROUGH = 3,
+    MOUNT_EXTERNAL_ANDROID_WRITABLE = 4,
+    MOUNT_EXTERNAL_COUNT = 5
 };
 
 // Must match values in com.android.internal.os.Zygote.
@@ -917,36 +904,6 @@
 }
 
 /**
- * A failure function used to report fatal errors to the managed runtime.  This
- * function is often curried with the process name information and then passed
- * to called functions.
- *
- * @param env  Managed runtime environment
- * @param process_name  A native representation of the process name
- * @param managed_process_name  A managed representation of the process name
- * @param msg  The error message to be reported
- */
-[[noreturn]]
-static void ZygoteFailure(JNIEnv* env,
-                          const char* process_name,
-                          jstring managed_process_name,
-                          const std::string& msg) {
-  std::unique_ptr<ScopedUtfChars> scoped_managed_process_name_ptr = nullptr;
-  if (managed_process_name != nullptr) {
-    scoped_managed_process_name_ptr.reset(new ScopedUtfChars(env, managed_process_name));
-    if (scoped_managed_process_name_ptr->c_str() != nullptr) {
-      process_name = scoped_managed_process_name_ptr->c_str();
-    }
-  }
-
-  const std::string& error_msg =
-      (process_name == nullptr) ? msg : StringPrintf("(%s) %s", process_name, msg.c_str());
-
-  env->FatalError(error_msg.c_str());
-  __builtin_unreachable();
-}
-
-/**
  * A helper method for converting managed strings to native strings.  A fatal
  * error is generated if a problem is encountered in extracting a non-null
  * string.
@@ -1073,86 +1030,6 @@
 #endif
 }
 
-// Utility routine to fork a process from the zygote.
-NO_PAC_FUNC
-static pid_t ForkCommon(JNIEnv* env, bool is_system_server,
-                        const std::vector<int>& fds_to_close,
-                        const std::vector<int>& fds_to_ignore,
-                        bool is_priority_fork) {
-  SetSignalHandlers();
-
-  // Curry a failure function.
-  auto fail_fn = std::bind(ZygoteFailure, env, is_system_server ? "system_server" : "zygote",
-                           nullptr, _1);
-
-  // Temporarily block SIGCHLD during forks. The SIGCHLD handler might
-  // log, which would result in the logging FDs we close being reopened.
-  // This would cause failures because the FDs are not allowlisted.
-  //
-  // Note that the zygote process is single threaded at this point.
-  BlockSignal(SIGCHLD, fail_fn);
-
-  // Close any logging related FDs before we start evaluating the list of
-  // file descriptors.
-  __android_log_close();
-  AStatsSocket_close();
-
-  // If this is the first fork for this zygote, create the open FD table.  If
-  // it isn't, we just need to check whether the list of open files has changed
-  // (and it shouldn't in the normal case).
-  if (gOpenFdTable == nullptr) {
-    gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, fail_fn);
-  } else {
-    gOpenFdTable->Restat(fds_to_ignore, fail_fn);
-  }
-
-  android_fdsan_error_level fdsan_error_level = android_fdsan_get_error_level();
-
-  // Purge unused native memory in an attempt to reduce the amount of false
-  // sharing with the child process.  By reducing the size of the libc_malloc
-  // region shared with the child process we reduce the number of pages that
-  // transition to the private-dirty state when malloc adjusts the meta-data
-  // on each of the pages it is managing after the fork.
-  mallopt(M_PURGE, 0);
-
-  pid_t pid = fork();
-
-  if (pid == 0) {
-    if (is_priority_fork) {
-      setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX);
-    } else {
-      setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MIN);
-    }
-
-    // The child process.
-    PAuthKeyChange(env);
-    PreApplicationInit();
-
-    // Clean up any descriptors which must be closed immediately
-    DetachDescriptors(env, fds_to_close, fail_fn);
-
-    // Invalidate the entries in the USAP table.
-    ClearUsapTable();
-
-    // Re-open all remaining open file descriptors so that they aren't shared
-    // with the zygote across a fork.
-    gOpenFdTable->ReopenOrDetach(fail_fn);
-
-    // Turn fdsan back on.
-    android_fdsan_set_error_level(fdsan_error_level);
-
-    // Reset the fd to the unsolicited zygote socket
-    gSystemServerSocketFd = -1;
-  } else {
-    ALOGD("Forked child process %d", pid);
-  }
-
-  // We blocked SIGCHLD prior to a fork, we unblock it here.
-  UnblockSignal(SIGCHLD, fail_fn);
-
-  return pid;
-}
-
 // Create an app data directory over tmpfs overlayed CE / DE storage, and bind mount it
 // from the actual app data directory in data mirror.
 static bool createAndMountAppData(std::string_view package_name,
@@ -1973,9 +1850,10 @@
   static int sUsapTableInsertIndex = 0;
 
   int search_index = sUsapTableInsertIndex;
-
   do {
     if (gUsapTable[search_index].SetIfInvalid(usap_pid, read_pipe_fd)) {
+      ++gUsapPoolCount;
+
       // Start our next search right after where we finished this one.
       sUsapTableInsertIndex = (search_index + 1) % gUsapTable.size();
 
@@ -1993,7 +1871,7 @@
 /**
  * Invalidates the entry in the USAPTable corresponding to the provided
  * process ID if it is present.  If an entry was removed the USAP pool
- * count is decremented.
+ * count is decremented. May be called from signal handler.
  *
  * @param usap_pid  Process ID of the USAP entry to invalidate
  * @return True if an entry was invalidated; false otherwise
@@ -2069,6 +1947,121 @@
 
 namespace android {
 
+/**
+ * A failure function used to report fatal errors to the managed runtime.  This
+ * function is often curried with the process name information and then passed
+ * to called functions.
+ *
+ * @param env  Managed runtime environment
+ * @param process_name  A native representation of the process name
+ * @param managed_process_name  A managed representation of the process name
+ * @param msg  The error message to be reported
+ */
+[[noreturn]]
+void zygote::ZygoteFailure(JNIEnv* env,
+                           const char* process_name,
+                           jstring managed_process_name,
+                           const std::string& msg) {
+  std::unique_ptr<ScopedUtfChars> scoped_managed_process_name_ptr = nullptr;
+  if (managed_process_name != nullptr) {
+    scoped_managed_process_name_ptr.reset(new ScopedUtfChars(env, managed_process_name));
+    if (scoped_managed_process_name_ptr->c_str() != nullptr) {
+      process_name = scoped_managed_process_name_ptr->c_str();
+    }
+  }
+
+  const std::string& error_msg =
+      (process_name == nullptr || process_name[0] == '\0') ?
+      msg : StringPrintf("(%s) %s", process_name, msg.c_str());
+
+  env->FatalError(error_msg.c_str());
+  __builtin_unreachable();
+}
+
+// Utility routine to fork a process from the zygote.
+NO_PAC_FUNC
+pid_t zygote::ForkCommon(JNIEnv* env, bool is_system_server,
+                         const std::vector<int>& fds_to_close,
+                         const std::vector<int>& fds_to_ignore,
+                         bool is_priority_fork,
+                         bool purge) {
+  SetSignalHandlers();
+
+  // Curry a failure function.
+  auto fail_fn = std::bind(zygote::ZygoteFailure, env,
+                           is_system_server ? "system_server" : "zygote",
+                           nullptr, _1);
+
+  // Temporarily block SIGCHLD during forks. The SIGCHLD handler might
+  // log, which would result in the logging FDs we close being reopened.
+  // This would cause failures because the FDs are not allowlisted.
+  //
+  // Note that the zygote process is single threaded at this point.
+  BlockSignal(SIGCHLD, fail_fn);
+
+  // Close any logging related FDs before we start evaluating the list of
+  // file descriptors.
+  __android_log_close();
+  AStatsSocket_close();
+
+  // If this is the first fork for this zygote, create the open FD table.  If
+  // it isn't, we just need to check whether the list of open files has changed
+  // (and it shouldn't in the normal case).
+  if (gOpenFdTable == nullptr) {
+    gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, fail_fn);
+  } else {
+    gOpenFdTable->Restat(fds_to_ignore, fail_fn);
+  }
+
+  android_fdsan_error_level fdsan_error_level = android_fdsan_get_error_level();
+
+  if (purge) {
+    // Purge unused native memory in an attempt to reduce the amount of false
+    // sharing with the child process.  By reducing the size of the libc_malloc
+    // region shared with the child process we reduce the number of pages that
+    // transition to the private-dirty state when malloc adjusts the meta-data
+    // on each of the pages it is managing after the fork.
+    mallopt(M_PURGE, 0);
+  }
+
+  pid_t pid = fork();
+
+  if (pid == 0) {
+    if (is_priority_fork) {
+      setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX);
+    } else {
+      setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MIN);
+    }
+
+    // The child process.
+    PAuthKeyChange(env);
+    PreApplicationInit();
+
+    // Clean up any descriptors which must be closed immediately
+    DetachDescriptors(env, fds_to_close, fail_fn);
+
+    // Invalidate the entries in the USAP table.
+    ClearUsapTable();
+
+    // Re-open all remaining open file descriptors so that they aren't shared
+    // with the zygote across a fork.
+    gOpenFdTable->ReopenOrDetach(fail_fn);
+
+    // Turn fdsan back on.
+    android_fdsan_set_error_level(fdsan_error_level);
+
+    // Reset the fd to the unsolicited zygote socket
+    gSystemServerSocketFd = -1;
+  } else {
+    ALOGD("Forked child process %d", pid);
+  }
+
+  // We blocked SIGCHLD prior to a fork, we unblock it here.
+  UnblockSignal(SIGCHLD, fail_fn);
+
+  return pid;
+}
+
 static void com_android_internal_os_Zygote_nativePreApplicationInit(JNIEnv*, jclass) {
   PreApplicationInit();
 }
@@ -2085,7 +2078,8 @@
     jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
 
     if (UNLIKELY(managed_fds_to_close == nullptr)) {
-      ZygoteFailure(env, "zygote", nice_name, "Zygote received a null fds_to_close vector.");
+      zygote::ZygoteFailure(env, "zygote", nice_name,
+                            "Zygote received a null fds_to_close vector.");
     }
 
     std::vector<int> fds_to_close =
@@ -2111,7 +2105,7 @@
         fds_to_ignore.push_back(gSystemServerSocketFd);
     }
 
-    pid_t pid = ForkCommon(env, false, fds_to_close, fds_to_ignore, true);
+    pid_t pid = zygote::ForkCommon(env, false, fds_to_close, fds_to_ignore, true);
 
     if (pid == 0) {
       SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
@@ -2146,10 +2140,10 @@
       fds_to_ignore.push_back(gSystemServerSocketFd);
   }
 
-  pid_t pid = ForkCommon(env, true,
-                         fds_to_close,
-                         fds_to_ignore,
-                         true);
+  pid_t pid = zygote::ForkCommon(env, true,
+                                 fds_to_close,
+                                 fds_to_ignore,
+                                 true);
   if (pid == 0) {
       // System server prcoess does not need data isolation so no need to
       // know pkg_data_info_list.
@@ -2189,58 +2183,74 @@
  * ensuring proper file descriptor hygiene.
  *
  * @param env  Managed runtime environment
- * @param read_pipe_fd  The read FD for the USAP reporting pipe.  Manually closed by blastlas
- * in managed code.
+ * @param read_pipe_fd  The read FD for the USAP reporting pipe.  Manually closed by the child
+ * in managed code. -1 indicates none.
  * @param write_pipe_fd  The write FD for the USAP reporting pipe.  Manually closed by the
- * zygote in managed code.
+ * zygote in managed code. -1 indicates none.
  * @param managed_session_socket_fds  A list of anonymous session sockets that must be ignored by
  * the FD hygiene code and automatically "closed" in the new USAP.
+ * @param args_known Arguments for specialization are available; no need to read from a socket
  * @param is_priority_fork  Controls the nice level assigned to the newly created process
- * @return
+ * @return child pid in the parent, 0 in the child
  */
 NO_PAC_FUNC
-static jint com_android_internal_os_Zygote_nativeForkUsap(JNIEnv* env,
-                                                          jclass,
-                                                          jint read_pipe_fd,
-                                                          jint write_pipe_fd,
-                                                          jintArray managed_session_socket_fds,
-                                                          jboolean is_priority_fork) {
-  std::vector<int> fds_to_close(MakeUsapPipeReadFDVector()),
-                   fds_to_ignore(fds_to_close);
-
+static jint com_android_internal_os_Zygote_nativeForkApp(JNIEnv* env,
+                                                         jclass,
+                                                         jint read_pipe_fd,
+                                                         jint write_pipe_fd,
+                                                         jintArray managed_session_socket_fds,
+                                                         jboolean args_known,
+                                                         jboolean is_priority_fork) {
   std::vector<int> session_socket_fds =
       ExtractJIntArray(env, "USAP", nullptr, managed_session_socket_fds)
           .value_or(std::vector<int>());
+  return zygote::forkApp(env, read_pipe_fd, write_pipe_fd, session_socket_fds,
+                            args_known == JNI_TRUE, is_priority_fork == JNI_TRUE, true);
+}
 
-  // The USAP Pool Event FD is created during the initialization of the
-  // USAP pool and should always be valid here.
+NO_PAC_FUNC
+int zygote::forkApp(JNIEnv* env,
+                    int read_pipe_fd,
+                    int write_pipe_fd,
+                    const std::vector<int>& session_socket_fds,
+                    bool args_known,
+                    bool is_priority_fork,
+                    bool purge) {
+
+  std::vector<int> fds_to_close(MakeUsapPipeReadFDVector()),
+                   fds_to_ignore(fds_to_close);
 
   fds_to_close.push_back(gZygoteSocketFD);
-  fds_to_close.push_back(gUsapPoolEventFD);
-  fds_to_close.insert(fds_to_close.end(), session_socket_fds.begin(), session_socket_fds.end());
   if (gSystemServerSocketFd != -1) {
       fds_to_close.push_back(gSystemServerSocketFd);
   }
+  if (args_known) {
+      fds_to_close.push_back(gUsapPoolSocketFD);
+  }
+  fds_to_close.insert(fds_to_close.end(), session_socket_fds.begin(), session_socket_fds.end());
 
-  fds_to_ignore.push_back(gZygoteSocketFD);
   fds_to_ignore.push_back(gUsapPoolSocketFD);
-  fds_to_ignore.push_back(gUsapPoolEventFD);
-  fds_to_ignore.push_back(read_pipe_fd);
-  fds_to_ignore.push_back(write_pipe_fd);
+  fds_to_ignore.push_back(gZygoteSocketFD);
+  if (read_pipe_fd != -1) {
+      fds_to_ignore.push_back(read_pipe_fd);
+  }
+  if (write_pipe_fd != -1) {
+      fds_to_ignore.push_back(write_pipe_fd);
+  }
   fds_to_ignore.insert(fds_to_ignore.end(), session_socket_fds.begin(), session_socket_fds.end());
+
+  if (gUsapPoolEventFD != -1) {
+      fds_to_close.push_back(gUsapPoolEventFD);
+      fds_to_ignore.push_back(gUsapPoolEventFD);
+  }
   if (gSystemServerSocketFd != -1) {
+      if (args_known) {
+          fds_to_close.push_back(gSystemServerSocketFd);
+      }
       fds_to_ignore.push_back(gSystemServerSocketFd);
   }
-
-  pid_t usap_pid = ForkCommon(env, /* is_system_server= */ false, fds_to_close, fds_to_ignore,
-                              is_priority_fork == JNI_TRUE);
-
-  if (usap_pid != 0) {
-    ++gUsapPoolCount;
-    AddUsapTableEntry(usap_pid, read_pipe_fd);
-  }
-
-  return usap_pid;
+  return zygote::ForkCommon(env, /* is_system_server= */ false, fds_to_close,
+                            fds_to_ignore, is_priority_fork == JNI_TRUE, purge);
 }
 
 static void com_android_internal_os_Zygote_nativeAllowFileAcrossFork(
@@ -2354,7 +2364,7 @@
    */
 
   if (!SetTaskProfiles(0, {})) {
-    ZygoteFailure(env, "zygote", nullptr, "Zygote SetTaskProfiles failed");
+    zygote::ZygoteFailure(env, "zygote", nullptr, "Zygote SetTaskProfiles failed");
   }
 }
 
@@ -2372,15 +2382,21 @@
   return managed_usap_fds;
 }
 
+/*
+ * Add the given pid and file descriptor to the Usap table. CriticalNative method.
+ */
+static void com_android_internal_os_Zygote_nativeAddUsapTableEntry(jint pid, jint read_pipe_fd) {
+  AddUsapTableEntry(pid, read_pipe_fd);
+}
+
 /**
- * A JNI wrapper around RemoveUsapTableEntry.
+ * A JNI wrapper around RemoveUsapTableEntry. CriticalNative method.
  *
  * @param env  Managed runtime environment
  * @param usap_pid  Process ID of the USAP entry to invalidate
  * @return  True if an entry was invalidated; false otherwise.
  */
-static jboolean com_android_internal_os_Zygote_nativeRemoveUsapTableEntry(JNIEnv* env, jclass,
-                                                                          jint usap_pid) {
+static jboolean com_android_internal_os_Zygote_nativeRemoveUsapTableEntry(jint usap_pid) {
   return RemoveUsapTableEntry(usap_pid);
 }
 
@@ -2395,7 +2411,8 @@
 static jint com_android_internal_os_Zygote_nativeGetUsapPoolEventFD(JNIEnv* env, jclass) {
   if (gUsapPoolEventFD == -1) {
     if ((gUsapPoolEventFD = eventfd(0, 0)) == -1) {
-      ZygoteFailure(env, "zygote", nullptr, StringPrintf("Unable to create eventfd: %s", strerror(errno)));
+      zygote::ZygoteFailure(env, "zygote", nullptr,
+                            StringPrintf("Unable to create eventfd: %s", strerror(errno)));
     }
   }
 
@@ -2438,12 +2455,12 @@
 }
 
 static void com_android_internal_os_Zygote_nativeBlockSigTerm(JNIEnv* env, jclass) {
-  auto fail_fn = std::bind(ZygoteFailure, env, "usap", nullptr, _1);
+  auto fail_fn = std::bind(zygote::ZygoteFailure, env, "usap", nullptr, _1);
   BlockSignal(SIGTERM, fail_fn);
 }
 
 static void com_android_internal_os_Zygote_nativeUnblockSigTerm(JNIEnv* env, jclass) {
-  auto fail_fn = std::bind(ZygoteFailure, env, "usap", nullptr, _1);
+  auto fail_fn = std::bind(zygote::ZygoteFailure, env, "usap", nullptr, _1);
   UnblockSignal(SIGTERM, fail_fn);
 }
 
@@ -2549,7 +2566,10 @@
          (void*)com_android_internal_os_Zygote_nativePreApplicationInit},
         {"nativeInstallSeccompUidGidFilter", "(II)V",
          (void*)com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter},
-        {"nativeForkUsap", "(II[IZ)I", (void*)com_android_internal_os_Zygote_nativeForkUsap},
+        {"nativeForkApp", "(II[IZZ)I", (void*)com_android_internal_os_Zygote_nativeForkApp},
+        // @CriticalNative
+        {"nativeAddUsapTableEntry", "(II)V",
+         (void*)com_android_internal_os_Zygote_nativeAddUsapTableEntry},
         {"nativeSpecializeAppProcess",
          "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/"
          "String;Z[Ljava/lang/String;[Ljava/lang/String;ZZ)V",
@@ -2558,6 +2578,10 @@
          (void*)com_android_internal_os_Zygote_nativeInitNativeState},
         {"nativeGetUsapPipeFDs", "()[I",
          (void*)com_android_internal_os_Zygote_nativeGetUsapPipeFDs},
+        // @CriticalNative
+        {"nativeAddUsapTableEntry", "(II)V",
+         (void*)com_android_internal_os_Zygote_nativeAddUsapTableEntry},
+        // @CriticalNative
         {"nativeRemoveUsapTableEntry", "(I)Z",
          (void*)com_android_internal_os_Zygote_nativeRemoveUsapTableEntry},
         {"nativeGetUsapPoolEventFD", "()I",
diff --git a/core/jni/com_android_internal_os_Zygote.h b/core/jni/com_android_internal_os_Zygote.h
new file mode 100644
index 0000000..d2da914
--- /dev/null
+++ b/core/jni/com_android_internal_os_Zygote.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#ifndef _COM_ANDROID_INTERNAL_OS_ZYGOTE_H
+#define _COM_ANDROID_INTERNAL_OS_ZYGOTE_H
+
+#define LOG_TAG "Zygote"
+#define ATRACE_TAG ATRACE_TAG_DALVIK
+
+/* Functions in the callchain during the fork shall not be protected with
+   Armv8.3-A Pointer Authentication, otherwise child will not be able to return. */
+#ifdef __ARM_FEATURE_PAC_DEFAULT
+#ifdef __ARM_FEATURE_BTI_DEFAULT
+#define NO_PAC_FUNC __attribute__((target("branch-protection=bti")))
+#else
+#define NO_PAC_FUNC __attribute__((target("branch-protection=none")))
+#endif /* __ARM_FEATURE_BTI_DEFAULT */
+#else /* !__ARM_FEATURE_PAC_DEFAULT */
+#define NO_PAC_FUNC
+#endif /* __ARM_FEATURE_PAC_DEFAULT */
+
+#include <jni.h>
+#include <vector>
+#include <android-base/stringprintf.h>
+
+#define CREATE_ERROR(...) StringPrintf("%s:%d: ", __FILE__, __LINE__). \
+                              append(StringPrintf(__VA_ARGS__))
+
+namespace android {
+namespace zygote {
+
+NO_PAC_FUNC
+pid_t ForkCommon(JNIEnv* env,bool is_system_server,
+                 const std::vector<int>& fds_to_close,
+                 const std::vector<int>& fds_to_ignore,
+                 bool is_priority_fork,
+                 bool purge = true);
+
+/**
+ * Fork a process. The pipe fds are used for usap communication, or -1 in
+ * other cases. Session_socket_fds are FDs used for zygote communication that must be dealt
+ * with hygienically, but are not otherwise used here. Args_known indicates that the process
+ * will be immediately specialized with arguments that are already known, so no usap
+ * communication is required. Is_priority_fork should be true if this is on the app startup
+ * critical path. Purge specifies that unused pages should be purged before the fork.
+ */
+NO_PAC_FUNC
+int forkApp(JNIEnv* env,
+            int read_pipe_fd,
+            int write_pipe_fd,
+            const std::vector<int>& session_socket_fds,
+            bool args_known,
+            bool is_priority_fork,
+            bool purge);
+
+[[noreturn]]
+void ZygoteFailure(JNIEnv* env,
+                   const char* process_name,
+                   jstring managed_process_name,
+                   const std::string& msg);
+
+}  // namespace zygote
+}  // namespace android
+
+#endif // _COM_ANDROID_INTERNAL_OS_ZYGOTE_
diff --git a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
new file mode 100644
index 0000000..011e8f8
--- /dev/null
+++ b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
@@ -0,0 +1,512 @@
+/*
+ * 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.
+ */
+
+#include "com_android_internal_os_Zygote.h"
+
+#include <algorithm>
+#include <android-base/logging.h>
+#include <async_safe/log.h>
+#include <cctype>
+#include <chrono>
+#include <core_jni_helpers.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <jni.h>
+#include <nativehelper/JNIHelp.h>
+#include <optional>
+#include <poll.h>
+#include <unistd.h>
+#include <utility>
+#include <utils/misc.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <vector>
+
+namespace android {
+
+using namespace std::placeholders;
+using android::base::StringPrintf;
+using android::zygote::ZygoteFailure;
+
+// WARNING: Knows a little about the wire protocol used to communicate with Zygote.
+// TODO: Fix error handling.
+
+constexpr size_t MAX_COMMAND_BYTES = 12200;
+constexpr size_t NICE_NAME_BYTES = 50;
+
+// A buffer optionally bundled with a file descriptor from which we can fill it.
+// Does not own the file descriptor; destroying a NativeCommandBuffer does not
+// close the descriptor.
+class NativeCommandBuffer {
+ public:
+  NativeCommandBuffer(int sourceFd): mEnd(0), mNext(0), mLinesLeft(0), mFd(sourceFd) {}
+
+  // Read mNext line from mFd, filling mBuffer from file descriptor, as needed.
+  // Return a pair of pointers pointing to the first character, and one past the
+  // mEnd of the line, i.e. at the newline. Returns nothing on failure.
+  template<class FailFn>
+  std::optional<std::pair<char*, char*>> readLine(FailFn fail_fn) {
+    char* result = mBuffer + mNext;
+    while (true) {
+      if (mNext == mEnd) {
+        if (mEnd == MAX_COMMAND_BYTES) {
+          return {};
+        }
+        if (mFd == -1) {
+          fail_fn("ZygoteCommandBuffer.readLine attempted to read from mFd -1");
+        }
+        ssize_t nread = TEMP_FAILURE_RETRY(read(mFd, mBuffer + mEnd, MAX_COMMAND_BYTES - mEnd));
+        if (nread <= 0) {
+          if (nread == 0) {
+            return {};
+          }
+          fail_fn(CREATE_ERROR("session socket read failed: %s", strerror(errno)));
+        } else if (nread == MAX_COMMAND_BYTES - mEnd) {
+          // This is pessimistic by one character, but close enough.
+          fail_fn("ZygoteCommandBuffer overflowed: command too long");
+        }
+        mEnd += nread;
+      }
+      // UTF-8 does not allow newline to occur as part of a multibyte character.
+      char* nl = static_cast<char *>(memchr(mBuffer + mNext, '\n', mEnd - mNext));
+      if (nl == nullptr) {
+        mNext = mEnd;
+      } else {
+        mNext = nl - mBuffer + 1;
+        if (--mLinesLeft < 0) {
+          fail_fn("ZygoteCommandBuffer.readLine attempted to read past mEnd of command");
+        }
+        return std::make_pair(result, nl);
+      }
+    }
+  }
+
+  void reset() {
+    mNext = 0;
+  }
+
+  // Make sure the current command is fully buffered, without reading past the current command.
+  template<class FailFn>
+  void readAllLines(FailFn fail_fn) {
+     while (mLinesLeft > 0) {
+       readLine(fail_fn);
+    }
+  }
+
+  void clear() {
+    // Don't bother to actually clear the buffer; it'll be unmapped in the child anyway.
+    reset();
+    mNiceName[0] = '\0';
+    mEnd = 0;
+  }
+
+  // Insert line into the mBuffer. Checks that the mBuffer is not associated with an mFd.
+  // Implicitly adds newline separators. Allows mBuffer contents to be explicitly set.
+  void insert(const char* line, size_t lineLen) {
+    DCHECK(mFd == -1);
+    CHECK(mEnd + lineLen < MAX_COMMAND_BYTES);
+    strncpy(mBuffer + mEnd, line, lineLen);
+    mBuffer[mEnd + lineLen] = '\n';
+    mEnd += lineLen + 1;
+  }
+
+  // Clear mBuffer, start reading new command, return the number of arguments, leaving mBuffer
+  // positioned at the beginning of first argument. Return 0 on EOF.
+  template<class FailFn>
+  int getCount(FailFn fail_fn) {
+    mLinesLeft = 1;
+    auto line = readLine(fail_fn);
+    if (!line.has_value()) {
+      return 0;
+    }
+    char* countString = line.value().first;  // Newline terminated.
+    long nArgs = atol(countString);
+    if (nArgs <= 0 || nArgs >= MAX_COMMAND_BYTES / 2) {
+      fail_fn(CREATE_ERROR("Unreasonable argument count %ld", nArgs));
+    }
+    mLinesLeft = nArgs;
+    return static_cast<int>(nArgs);
+  }
+
+  // Is the mBuffer a simple fork command?
+  // We disallow request to wrap the child process, child zygotes, anything that
+  // mentions capabilities or requests uid < minUid.
+  // We insist that --setuid and --setgid arguments are explicitly included and that the
+  // command starts with --runtime-args.
+  // Assumes we are positioned at the beginning of the command after the argument count,
+  // and leaves the position at some indeterminate position in the buffer.
+  // As a side effect, this sets mNiceName to a non-empty string, if possible.
+  template<class FailFn>
+  bool isSimpleForkCommand(int minUid, FailFn fail_fn) {
+    if (mLinesLeft <= 0 || mLinesLeft  >= MAX_COMMAND_BYTES / 2) {
+      return false;
+    }
+    static const char* RUNTIME_ARGS = "--runtime-args";
+    static const char* INVOKE_WITH = "--invoke-with";
+    static const char* CHILD_ZYGOTE = "--start-child-zygote";
+    static const char* SETUID = "--setuid=";
+    static const char* SETGID = "--setgid=";
+    static const char* CAPABILITIES = "--capabilities";
+    static const char* NICE_NAME = "--nice-name=";
+    static const size_t RA_LENGTH = strlen(RUNTIME_ARGS);
+    static const size_t IW_LENGTH = strlen(INVOKE_WITH);
+    static const size_t CZ_LENGTH = strlen(CHILD_ZYGOTE);
+    static const size_t SU_LENGTH = strlen(SETUID);
+    static const size_t SG_LENGTH = strlen(SETGID);
+    static const size_t CA_LENGTH = strlen(CAPABILITIES);
+    static const size_t NN_LENGTH = strlen(NICE_NAME);
+
+    bool saw_setuid = false, saw_setgid = false;
+    bool saw_runtime_args = false;
+
+    while (mLinesLeft > 0) {
+      auto read_result = readLine(fail_fn);
+      if (!read_result.has_value()) {
+        return false;
+      }
+      auto [arg_start, arg_end] = read_result.value();
+      if (arg_end - arg_start == RA_LENGTH
+          && strncmp(arg_start, RUNTIME_ARGS, RA_LENGTH) == 0) {
+        saw_runtime_args = true;
+        continue;
+      }
+      if (arg_end - arg_start >= NN_LENGTH
+          && strncmp(arg_start, NICE_NAME, NN_LENGTH) == 0) {
+        size_t name_len = arg_end - (arg_start + NN_LENGTH);
+        size_t copy_len = std::min(name_len, NICE_NAME_BYTES - 1);
+        memcpy(mNiceName, arg_start + NN_LENGTH, copy_len);
+        mNiceName[copy_len] = '\0';
+        continue;
+      }
+      if (arg_end - arg_start == IW_LENGTH
+          && strncmp(arg_start, INVOKE_WITH, IW_LENGTH) == 0) {
+        // This also removes the need for invoke-with security checks here.
+        return false;
+      }
+      if (arg_end - arg_start == CZ_LENGTH
+          && strncmp(arg_start, CHILD_ZYGOTE, CZ_LENGTH) == 0) {
+        return false;
+      }
+      if (arg_end - arg_start >= CA_LENGTH
+          && strncmp(arg_start, CAPABILITIES, CA_LENGTH) == 0) {
+        return false;
+      }
+      if (arg_end - arg_start >= SU_LENGTH
+          && strncmp(arg_start, SETUID, SU_LENGTH) == 0) {
+        int uid = digitsVal(arg_start + SU_LENGTH, arg_end);
+        if (uid < minUid) {
+          return false;
+        }
+        saw_setuid = true;
+        continue;
+      }
+      if (arg_end - arg_start >= SG_LENGTH
+          && strncmp(arg_start, SETGID, SG_LENGTH) == 0) {
+        int gid = digitsVal(arg_start + SG_LENGTH, arg_end);
+        if (gid == -1) {
+          return false;
+        }
+        saw_setgid = true;
+      }
+    }
+    return saw_runtime_args && saw_setuid && saw_setgid;
+  }
+
+  void setFd(int new_fd) {
+    mFd = new_fd;
+  }
+
+  int getFd() const {
+    return mFd;
+  }
+
+  const char* niceNameAddr() const {
+    return mNiceName;
+  }
+
+  // Debug only:
+  void logState() const {
+    ALOGD("mbuffer starts with %c%c, nice name is %s, "
+          "mEnd = %u, mNext = %u, mLinesLeft = %d, mFd = %d",
+          mBuffer[0], (mBuffer[1] == '\n' ? ' ' : mBuffer[1]),
+          niceNameAddr(),
+          static_cast<unsigned>(mEnd), static_cast<unsigned>(mNext),
+          static_cast<int>(mLinesLeft), mFd);
+  }
+
+ private:
+  // Picky version of atoi(). No sign or unexpected characters allowed. Return -1 on failure.
+  static int digitsVal(char* start, char* end) {
+    int result = 0;
+    if (end - start > 6) {
+      return -1;
+    }
+    for (char* dp = start; dp < end; ++dp) {
+      if (*dp < '0' || *dp > '9') {
+        ALOGW("Argument failed integer format check");
+        return -1;
+      }
+      result = 10 * result + (*dp - '0');
+    }
+    return result;
+  }
+
+  uint32_t mEnd;  // Index of first empty byte in the mBuffer.
+  uint32_t mNext;  // Index of first character past last line returned by readLine.
+  int32_t mLinesLeft;  // Lines in current command that haven't yet been read.
+  int mFd;  // Open file descriptor from which we can read more. -1 if none.
+  char mNiceName[NICE_NAME_BYTES];
+  char mBuffer[MAX_COMMAND_BYTES];
+};
+
+static_assert(sizeof(NativeCommandBuffer) < 3 * 4096);
+
+static int buffersAllocd(0);
+
+// Get a new NativeCommandBuffer. Can only be called once between freeNativeBuffer calls,
+// so that only one buffer exists at a time.
+jlong com_android_internal_os_ZygoteCommandBuffer_getNativeBuffer(JNIEnv* env, jclass, jint fd) {
+  CHECK(buffersAllocd == 0);
+  ++buffersAllocd;
+  // MMap explicitly to get it page aligned.
+  void *bufferMem = mmap(NULL, sizeof(NativeCommandBuffer), PROT_READ | PROT_WRITE,
+                         MAP_ANONYMOUS | MAP_PRIVATE | MAP_POPULATE, -1, 0);
+  // Currently we mmap and unmap one for every request handled by the Java code.
+  // That could be improved, but unclear it matters.
+  if (bufferMem == MAP_FAILED) {
+    ZygoteFailure(env, nullptr, nullptr, "Failed to map argument buffer");
+  }
+  return (jlong) new(bufferMem) NativeCommandBuffer(fd);
+}
+
+// Delete native command buffer.
+void com_android_internal_os_ZygoteCommandBuffer_freeNativeBuffer(JNIEnv* env, jclass,
+                                                                  jlong j_buffer) {
+  CHECK(buffersAllocd == 1);
+  NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer);
+  n_buffer->~NativeCommandBuffer();
+  if (munmap(n_buffer, sizeof(NativeCommandBuffer)) != 0) {
+    ZygoteFailure(env, nullptr, nullptr, "Failed to unmap argument buffer");
+  }
+  --buffersAllocd;
+}
+
+// Clear the buffer, read the line containing the count, and return the count.
+jint com_android_internal_os_ZygoteCommandBuffer_nativeGetCount(JNIEnv* env, jclass,
+                                                                jlong j_buffer) {
+  NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer);
+  auto fail_fn = std::bind(ZygoteFailure, env, nullptr, nullptr, _1);
+  return n_buffer->getCount(fail_fn);
+}
+
+// Explicitly insert a string as the last line (argument) of the buffer.
+void com_android_internal_os_ZygoteCommandBuffer_insert(JNIEnv* env, jclass, jlong j_buffer,
+                                                        jstring line) {
+  NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer);
+  size_t lineLen = static_cast<size_t>(env->GetStringUTFLength(line));
+  const char* cstring = env->GetStringUTFChars(line, NULL);
+  n_buffer->insert(cstring, lineLen);
+  env->ReleaseStringUTFChars(line, cstring);
+}
+
+// Read a line from the buffer, refilling as necessary.
+jstring com_android_internal_os_ZygoteCommandBuffer_nativeNextArg(JNIEnv* env, jclass,
+                                                                  jlong j_buffer) {
+  NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer);
+  auto fail_fn = std::bind(ZygoteFailure, env, n_buffer->niceNameAddr(), nullptr, _1);
+  auto line = n_buffer->readLine(fail_fn);
+  if (!line.has_value()) {
+    fail_fn("Incomplete zygote command");
+  }
+  auto [cresult, endp] = line.value();
+  // OK to temporarily clobber the buffer, since this is not thread safe, and we're modifying
+  // the buffer anyway.
+  *endp = '\0';
+  jstring result = env->NewStringUTF(cresult);
+  *endp = '\n';
+  return result;
+}
+
+// Read all lines from the current command into the buffer, and then reset the buffer, so
+// we will start reading again at the beginning of the command, starting with the argument
+// count. And we don't need access to the fd to do so.
+void com_android_internal_os_ZygoteCommandBuffer_nativeReadFullyAndReset(JNIEnv* env, jclass,
+                                                                         jlong j_buffer) {
+  NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer);
+  auto fail_fn = std::bind(ZygoteFailure, env, n_buffer->niceNameAddr(), nullptr, _1);
+  n_buffer->readAllLines(fail_fn);
+  n_buffer->reset();
+}
+
+// Fork a child as specified by the current command buffer, and refill the command
+// buffer from the given socket. So long as the result is another simple fork command,
+// repeat this process.
+// It must contain a fork command, which is currently restricted not to fork another
+// zygote or involve a wrapper process.
+// The initial buffer should be partially or entirely read; we read it fully and reset it.
+// When we return, the buffer contains the command we couldn't handle, and has been reset().
+// We return false in the parent when we see a command we didn't understand, and thus the
+// command in the buffer still needs to be executed.
+// We return true in each child.
+// We only process fork commands if the peer uid matches expected_uid.
+// For every fork command after the first, we check that the requested uid is at
+// least minUid.
+NO_PAC_FUNC
+jboolean com_android_internal_os_ZygoteCommandBuffer_nativeForkRepeatedly(
+            JNIEnv* env,
+            jclass,
+            jlong j_buffer,
+            jint zygote_socket_fd,
+            jint expected_uid,
+            jint minUid,
+            jstring managed_nice_name) {
+
+  NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer);
+  int session_socket = n_buffer->getFd();
+  std::vector<int> session_socket_fds {session_socket};
+  auto fail_fn_1 = std::bind(ZygoteFailure, env, static_cast<const char*>(nullptr),
+                             static_cast<jstring>(managed_nice_name), _1);
+  // This binds to the nice name address; the actual names are updated by isSimpleForkCommand:
+  auto fail_fn_n = std::bind(ZygoteFailure, env, n_buffer->niceNameAddr(),
+                             static_cast<jstring>(nullptr), _1);
+  auto fail_fn_z = std::bind(ZygoteFailure, env, "zygote", nullptr, _1);
+
+  struct pollfd fd_structs[2];
+  static const int ZYGOTE_IDX = 0;
+  static const int SESSION_IDX = 1;
+  fd_structs[ZYGOTE_IDX].fd = zygote_socket_fd;
+  fd_structs[ZYGOTE_IDX].events = POLLIN;
+  fd_structs[SESSION_IDX].fd = session_socket;
+  fd_structs[SESSION_IDX].events = POLLIN;
+
+  struct timeval timeout;
+  socklen_t timeout_size = sizeof timeout;
+  if (getsockopt(session_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, &timeout_size) != 0) {
+    fail_fn_z("Failed to retrieve session socket timeout");
+  }
+
+  struct ucred credentials;
+  socklen_t cred_size = sizeof credentials;
+  if (getsockopt(n_buffer->getFd(), SOL_SOCKET, SO_PEERCRED, &credentials, &cred_size) == -1
+      || cred_size != sizeof credentials) {
+    fail_fn_1("ForkMany failed to get initial credentials, %s", strerror(errno));
+  }
+
+  bool first_time = true;
+  do {
+    if (credentials.uid != expected_uid) {
+      return JNI_FALSE;
+    }
+    n_buffer->readAllLines(first_time ? fail_fn_1 : fail_fn_n);
+    n_buffer->reset();
+    int pid = zygote::forkApp(env, /* no pipe FDs */ -1, -1, session_socket_fds,
+                              /*args_known=*/ true, /*is_priority_fork=*/ true,
+                              /*purge=*/ first_time);
+    if (pid == 0) {
+      return JNI_TRUE;
+    }
+    // We're in the parent. Write big-endian pid, followed by a boolean.
+    char pid_buf[5];
+    int tmp_pid = pid;
+    for (int i = 3; i >= 0; --i) {
+      pid_buf[i] = tmp_pid & 0xff;
+      tmp_pid >>= 8;
+    }
+    pid_buf[4] = 0;  // Process is not wrapped.
+    int res = write(session_socket, pid_buf, 5);
+    if (res != 5) {
+      if (res == -1) {
+        (first_time ? fail_fn_1 : fail_fn_n)
+            (CREATE_ERROR("Pid write error %d: %s", errno, strerror(errno)));
+      } else {
+        (first_time ? fail_fn_1 : fail_fn_n)
+            (CREATE_ERROR("Write unexpectedly returned short: %d < 5", res));
+      }
+    }
+    // Clear buffer and get count from next command.
+    n_buffer->clear();
+    for (;;) {
+      // Poll isn't strictly necessary for now. But without it, disconnect is hard to detect.
+      int poll_res = TEMP_FAILURE_RETRY(poll(fd_structs, 2, -1 /* infinite timeout */));
+      if ((fd_structs[SESSION_IDX].revents & POLLIN) != 0) {
+        if (n_buffer->getCount(fail_fn_z) != 0) {
+          break;
+        }  // else disconnected;
+      } else if (poll_res == 0 || (fd_structs[ZYGOTE_IDX].revents & POLLIN) == 0) {
+        fail_fn_z(
+            CREATE_ERROR("Poll returned with no descriptors ready! Poll returned %d", poll_res));
+      }
+      // We've now seen either a disconnect or connect request.
+      close(session_socket);
+      int new_fd = accept(zygote_socket_fd, nullptr, nullptr);
+      if (new_fd == -1) {
+        fail_fn_z("Accept(%d) failed: %s", zygote_socket_fd, strerror(errno));
+      }
+      if (new_fd != session_socket) {
+          // Move new_fd back to the old value, so that we don't have to change Java-level data
+          // structures to reflect a change. This implicitly closes the old one.
+          if (dup2(new_fd, session_socket) != session_socket) {
+            fail_fn_z(CREATE_ERROR("Failed to move fd %d to %d: %s",
+                                   new_fd, session_socket, strerror(errno)));
+          }
+          close(new_fd);
+      }
+      // If we ever return, we effectively reuse the old Java ZygoteConnection.
+      // None of its state needs to change.
+      if (setsockopt(session_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, timeout_size) != 0) {
+        fail_fn_z(CREATE_ERROR("Failed to set receive timeout for socket %d: %s",
+                               session_socket, strerror(errno)));
+      }
+      if (setsockopt(session_socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, timeout_size) != 0) {
+        fail_fn_z(CREATE_ERROR("Failed to set send timeout for socket %d: %s",
+                               session_socket, strerror(errno)));
+      }
+      if (getsockopt(session_socket, SOL_SOCKET, SO_PEERCRED, &credentials, &cred_size) == -1) {
+        fail_fn_z(CREATE_ERROR("ForkMany failed to get credentials: %s", strerror(errno)));
+      }
+      if (cred_size != sizeof credentials) {
+        fail_fn_z(CREATE_ERROR("ForkMany credential size = %d, should be %d",
+                               cred_size, static_cast<int>(sizeof credentials)));
+      }
+    }
+    first_time = false;
+  } while (n_buffer->isSimpleForkCommand(minUid, fail_fn_n));
+  ALOGW("forkRepeatedly terminated due to non-simple command");
+  n_buffer->logState();
+  n_buffer->reset();
+  return JNI_FALSE;
+}
+
+#define METHOD_NAME(m) com_android_internal_os_ZygoteCommandBuffer_ ## m
+
+static const JNINativeMethod gMethods[] = {
+        {"getNativeBuffer", "(I)J", (void *) METHOD_NAME(getNativeBuffer)},
+        {"freeNativeBuffer", "(J)V", (void *) METHOD_NAME(freeNativeBuffer)},
+        {"insert", "(JLjava/lang/String;)V", (void *) METHOD_NAME(insert)},
+        {"nativeNextArg", "(J)Ljava/lang/String;", (void *) METHOD_NAME(nativeNextArg)},
+        {"nativeReadFullyAndReset", "(J)V", (void *) METHOD_NAME(nativeReadFullyAndReset)},
+        {"nativeGetCount", "(J)I", (void *) METHOD_NAME(nativeGetCount)},
+        {"nativeForkRepeatedly", "(JIIILjava/lang/String;)Z",
+          (void *) METHOD_NAME(nativeForkRepeatedly)},
+};
+
+int register_com_android_internal_os_ZygoteCommandBuffer(JNIEnv* env) {
+  return RegisterMethodsOrDie(env, "com/android/internal/os/ZygoteCommandBuffer", gMethods,
+                              NELEM(gMethods));
+}
+
+}  // namespace android
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index 99fd215..e62b5c1 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -15,6 +15,7 @@
 ogunwale@google.com
 jjaggi@google.com
 roosa@google.com
+per-file package_item_info.proto = toddke@google.com
 per-file usagestatsservice.proto, usagestatsservice_v2.proto = mwachens@google.com
 per-file apphibernationservice.proto = file:/core/java/android/apphibernation/OWNERS
 
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index c580b34..ad1d252 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -282,7 +282,8 @@
         optional SettingProto force_rtl = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto emulate_display_cutout = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto force_desktop_mode_on_external_displays = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
-        optional SettingProto enable_sizecompat_freeform = 7 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // Deprecated, use enable_non_resizable_multi_window
+        optional SettingProto enable_sizecompat_freeform = 7 [ (android.privacy).dest = DEST_AUTOMATIC, deprecated = true ];
         optional SettingProto enable_non_resizable_multi_window = 8 [ (android.privacy).dest = DEST_AUTOMATIC ];
     }
     optional Development development = 39;
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index d3c2d31..ec41a47 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -627,6 +627,7 @@
         optional int64 duration_ms = 2;
         optional string tag = 3;
         optional int32 type = 4;
+        optional int32 reason_code = 5;
     }
     repeated PendingTempWhitelist pending_temp_whitelist = 26;
 
diff --git a/core/proto/android/server/powerstatsservice.proto b/core/proto/android/server/powerstatsservice.proto
index 4b1ee02..f64e146 100644
--- a/core/proto/android/server/powerstatsservice.proto
+++ b/core/proto/android/server/powerstatsservice.proto
@@ -144,7 +144,7 @@
      */
     optional int64 total_state_entry_count = 3;
     /**
-     * Last time this state was entered. Time in milliseconds since boot
+     * Last time this state was entered. Walltime in milliseconds since Unix epoch.
      */
     optional int64 last_entry_timestamp_ms = 4;
 }
@@ -208,7 +208,7 @@
     /** Unique index identifying the energy consumer. */
     optional int32 id = 1;
 
-    /** Time since device boot(CLOCK_BOOTTIME) in milli-seconds */
+    /** Walltime in milliseconds since Unix epoch */
     optional int64 timestamp_ms = 2;
 
     /** Accumulated energy since device boot in microwatt-seconds (uWs) */
@@ -247,7 +247,7 @@
      */
     optional int32 id = 1;
 
-    /** Time since device boot(CLOCK_BOOTTIME) in milli-seconds */
+    /** Walltime in milliseconds since Unix epoch */
     optional int64 timestamp_ms = 2;
 
     /** Accumulated energy since device boot in microwatt-seconds (uWs) */
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index a1be865c..f26bf7c 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -174,10 +174,10 @@
     // Use root_display_area instead
     optional WindowContainerProto window_container = 1 [deprecated=true];
     optional int32 id = 2;
-    reserved 3; // stacks
-    optional DockedStackDividerControllerProto docked_stack_divider_controller = 4 [deprecated=true];
+    reserved 3; // RootTasks
+    optional DockedTaskDividerControllerProto docked_task_divider_controller = 4 [deprecated=true];
     // Will be removed soon.
-    optional PinnedStackControllerProto pinned_stack_controller = 5 [deprecated=true];
+    optional PinnedTaskControllerProto pinned_task_controller = 5 [deprecated=true];
     /* non app windows */
     repeated WindowTokenProto above_app_windows = 6 [deprecated=true];
     repeated WindowTokenProto below_app_windows = 7 [deprecated=true];
@@ -256,15 +256,15 @@
     optional int32 last_orientation = 5 [(.android.typedef) = "android.content.pm.ActivityInfo.ScreenOrientation"];
 }
 
-/* represents DockedStackDividerController */
-message DockedStackDividerControllerProto {
+/* represents DockedTaskDividerController */
+message DockedTaskDividerControllerProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
     optional bool minimized_dock = 1 [deprecated=true];
 }
 
-/* represents PinnedStackController */
-message PinnedStackControllerProto {
+/* represents PinnedTaskController */
+message PinnedTaskControllerProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
     optional .android.graphics.RectProto default_bounds = 1 [deprecated=true];
@@ -337,7 +337,7 @@
     optional bool starting_displayed = 20;
     optional bool starting_moved = 201;
     optional bool visible_set_from_transferred_starting_window = 22;
-    repeated .android.graphics.RectProto frozen_bounds = 23;
+    repeated .android.graphics.RectProto frozen_bounds = 23 [deprecated=true];
     optional bool visible = 24;
     reserved 25; // configuration_container
     optional IdentifierProto identifier = 26 [deprecated=true];
diff --git a/core/proto/android/service/netstats.proto b/core/proto/android/service/netstats.proto
index 8ebb4a9..c8cdfdd 100644
--- a/core/proto/android/service/netstats.proto
+++ b/core/proto/android/service/netstats.proto
@@ -80,6 +80,8 @@
     optional bool metered = 5;
 
     optional bool default_network = 6;
+
+    optional int32 oem_managed_network = 7;
 }
 
 // Corresponds to NetworkStatsRecorder.
diff --git a/core/res/Android.bp b/core/res/Android.bp
index 4cf9cfb..b988b5a 100644
--- a/core/res/Android.bp
+++ b/core/res/Android.bp
@@ -44,11 +44,73 @@
     ],
 }
 
+genrule {
+    name: "remote-color-resources-compile-public",
+    tools: ["aapt2"],
+    srcs: [
+        "remote_color_resources_res/values/public.xml",
+    ],
+    out: ["values_public.arsc.flat"],
+    cmd: "$(location aapt2) compile $(in) -o $(genDir)",
+}
+
+genrule {
+    name: "remote-color-resources-compile-colors",
+    tools: ["aapt2"],
+    srcs: [
+        "remote_color_resources_res/values/colors.xml",
+    ],
+    out: ["values_colors.arsc.flat"],
+    cmd: "$(location aapt2) compile $(in) -o $(genDir)",
+}
+
+genrule {
+    name: "remote-color-resources-apk",
+    tools: ["aapt2"],
+    // The first input file in the list must be the manifest
+    srcs: [
+        "RemoteThemeColorsAndroidManifest.xml",
+        ":remote-color-resources-compile-public",
+        ":remote-color-resources-compile-colors",
+    ],
+    out: ["remote-color-resources.apk"],
+    cmd: "$(location aapt2) link -o $(out) --manifest $(in)"
+}
+
+genrule {
+    name: "remote-color-resources-arsc",
+    srcs: [":remote-color-resources-apk"],
+    out: ["res/raw/remote_views_color_resources.arsc"],
+    cmd: "mkdir -p $(genDir)/remote-color-resources-arsc && "
+        + "unzip -x $(in) resources.arsc -d $(genDir)/remote-color-resources-arsc && "
+        + "mkdir -p $$(dirname $(out)) && "
+        + "mv $(genDir)/remote-color-resources-arsc/resources.arsc $(out) && "
+        + "echo 'Created $(out)'"
+}
+
+genrule {
+    name: "remote-color-resources-arsc-zip",
+    tools: ["soong_zip"],
+    srcs: [
+        ":remote-color-resources-arsc",
+        "remote_color_resources_res/symbols.xml",
+    ],
+    out: ["remote_views_color_resources.zip"],
+    cmd: "INPUTS=($(in)) && "
+        + "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) ."
+}
+
 android_app {
     name: "framework-res",
     sdk_version: "core_platform",
     certificate: "platform",
 
+    srcs: [":remote-color-resources-arsc"],
+
     // Disable dexpreopt and verify_uses_libraries check as the app
     // contains no Java code to be dexpreopted.
     enforce_uses_libs: false,
@@ -72,6 +134,10 @@
         "--auto-add-overlay",
     ],
 
+    resource_zips: [
+        ":remote-color-resources-arsc-zip",
+    ],
+
     // Create package-export.apk, which other packages can use to get
     // PRODUCT-agnostic resource data like IDs and type definitions.
     export_package_resources: true,
@@ -96,6 +162,7 @@
     srcs: [
         "assets/**/*",
         "res/**/*",
+        ":remote-color-resources-arsc",
     ],
 }
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5dd8580..50d1e6b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1284,15 +1284,15 @@
         android:backgroundPermission="android.permission.RECORD_BACKGROUND_AUDIO"
         android:protectionLevel="dangerous|instant" />
 
-    <!-- Allows an application to record audio while in the background.
-         <p>Protection level: dangerous
-    -->
+    <!-- @SystemApi @TestApi Allows an application to record audio while in the background.
+         This permission is not intended to be held by apps.
+         <p>Protection level: internal
+        @hide -->
     <permission android:name="android.permission.RECORD_BACKGROUND_AUDIO"
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_recordBackgroundAudio"
         android:description="@string/permdesc_recordBackgroundAudio"
-        android:permissionFlags="hardRestricted|installerExemptIgnored"
-        android:protectionLevel="dangerous" />
+        android:protectionLevel="internal" />
 
     <!-- ====================================================================== -->
     <!-- Permissions for activity recognition                        -->
@@ -1368,15 +1368,15 @@
         android:backgroundPermission="android.permission.BACKGROUND_CAMERA"
         android:protectionLevel="dangerous|instant" />
 
-    <!-- Required to be able to access the camera device in the background.
-         <p>Protection level: dangerous
-    -->
+    <!-- @SystemApi @TestApi Required to be able to access the camera device in the background.
+         This permission is not intended to be held by apps.
+         <p>Protection level: internal
+        @hide -->
     <permission android:name="android.permission.BACKGROUND_CAMERA"
             android:permissionGroup="android.permission-group.UNDEFINED"
             android:label="@string/permlab_backgroundCamera"
             android:description="@string/permdesc_backgroundCamera"
-            android:permissionFlags="hardRestricted|installerExemptIgnored"
-            android:protectionLevel="dangerous" />
+            android:protectionLevel="internal" />
 
     <!-- @SystemApi Required in addition to android.permission.CAMERA to be able to access
            system only camera devices.
@@ -1886,6 +1886,11 @@
     <permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS"
                 android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi @hide Allows system APK to manage country code.
+             <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.MANAGE_WIFI_COUNTRY_CODE"
+        android:protectionLevel="signature" />
+
     <!-- @SystemApi @hide Allows an application to manage an automotive device's application network
          preference as it relates to OEM_PAID and OEM_PRIVATE capable networks.
          <p>Not for use by third-party or privileged applications. -->
@@ -2371,6 +2376,15 @@
     <permission android:name="android.permission.BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE"
         android:protectionLevel="signature" />
 
+    <!-- Must be required by a {@link android.telecom.CallDiagnosticService},
+         to ensure that only the system can bind to it.
+         <p>Protection level: signature
+         @SystemApi
+         @hide
+    -->
+    <permission android:name="android.permission.BIND_CALL_DIAGNOSTIC_SERVICE"
+        android:protectionLevel="signature" />
+
     <!-- Must be required by a {@link android.telecom.CallRedirectionService},
          to ensure that only the system can bind to it.
          <p>Protection level: signature|privileged
@@ -2641,6 +2655,16 @@
         android:label="@string/permlab_manageProfileAndDeviceOwners"
         android:description="@string/permdesc_manageProfileAndDeviceOwners" />
 
+    <!-- @TestApi @hide Allows an application to reset the record of previous system update freeze
+         periods. -->
+    <permission android:name="android.permission.CLEAR_FREEZE_PERIOD"
+                android:protectionLevel="signature" />
+
+    <!-- @TestApi @hide Allows an application to force available DevicePolicyManager logs to
+         DPC. -->
+    <permission android:name="android.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS"
+                android:protectionLevel="signature" />
+
     <!-- Allows an application to get full detailed information about
          recently running tasks, with full fidelity to the real state.
          @hide -->
@@ -3972,17 +3996,6 @@
     <permission android:name="com.android.permission.INSTALL_EXISTING_PACKAGES"
         android:protectionLevel="signature|privileged" />
 
-    <!-- Allows an application to use the package installer v2 APIs.
-         <p>The package installer v2 APIs are still a work in progress and we're
-         currently validating they work in all scenarios.
-         <p>Not for use by third-party applications.
-         TODO(b/152310230): use this permission to protect only Incremental installations
-         once the APIs are confirmed to be sufficient.
-         @hide
-    -->
-    <permission android:name="com.android.permission.USE_INSTALLER_V2"
-        android:protectionLevel="signature|verifier" />
-
     <!-- Allows an application to use System Data Loaders.
          <p>Not for use by third-party applications.
          @hide
@@ -5421,6 +5434,12 @@
          @hide -->
     <permission android:name="android.permission.MANAGE_SENSOR_PRIVACY"
                 android:protectionLevel="signature" />
+
+    <!-- @SystemApi Allows sensor privacy changes to be observed.
+         @hide -->
+    <permission android:name="android.permission.OBSERVE_SENSOR_PRIVACY"
+                android:protectionLevel="signature|installer" />
+
     <!-- @SystemApi Permission that protects the {@link Intent#ACTION_REVIEW_ACCESSIBILITY_SERVICES}
          intent.
          @hide -->
diff --git a/core/res/RemoteThemeColorsAndroidManifest.xml b/core/res/RemoteThemeColorsAndroidManifest.xml
new file mode 100644
index 0000000..11970fd
--- /dev/null
+++ b/core/res/RemoteThemeColorsAndroidManifest.xml
@@ -0,0 +1,5 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+  package="android">
+<application/>
+</manifest>
+
diff --git a/core/res/remote_color_resources_res/symbols.xml b/core/res/remote_color_resources_res/symbols.xml
new file mode 100644
index 0000000..82d5e3e
--- /dev/null
+++ b/core/res/remote_color_resources_res/symbols.xml
@@ -0,0 +1,4 @@
+<resources>
+  <!-- ARSC file used to overlay local colors when rendering a RemoteViews -->
+  <java-symbol type="raw" name="remote_views_color_resources" />
+</resources>
diff --git a/core/res/remote_color_resources_res/values/colors.xml b/core/res/remote_color_resources_res/values/colors.xml
new file mode 100644
index 0000000..295f16e
--- /dev/null
+++ b/core/res/remote_color_resources_res/values/colors.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+  <!-- Note: the values of the colors doesn't really matter (they will always be overwritten before used), but they help a lot debugging, to find out which color is where in the ARSC file. -->
+  <color name="system_primary_0">#01010101</color>
+  <color name="system_primary_50">#02020202</color>
+  <color name="system_primary_100">#03030303</color>
+  <color name="system_primary_200">#04040404</color>
+  <color name="system_primary_300">#05050505</color>
+  <color name="system_primary_400">#06060606</color>
+  <color name="system_primary_500">#07070707</color>
+  <color name="system_primary_600">#08080808</color>
+  <color name="system_primary_700">#09090909</color>
+  <color name="system_primary_800">#0a0a0a0a</color>
+  <color name="system_primary_900">#0b0b0b0b</color>
+  <color name="system_primary_1000">#0c0c0c0c</color>
+  <color name="system_secondary_0">#10101010</color>
+  <color name="system_secondary_50">#20202020</color>
+  <color name="system_secondary_100">#30303030</color>
+  <color name="system_secondary_200">#40404040</color>
+  <color name="system_secondary_300">#50505050</color>
+  <color name="system_secondary_400">#60606060</color>
+  <color name="system_secondary_500">#70707070</color>
+  <color name="system_secondary_600">#80808080</color>
+  <color name="system_secondary_700">#90909090</color>
+  <color name="system_secondary_800">#a0a0a0a0</color>
+  <color name="system_secondary_900">#b0b0b0b0</color>
+  <color name="system_secondary_1000">#c0c0c0c0</color>
+  <color name="system_neutral_0">#1f1f1f1f</color>
+  <color name="system_neutral_50">#2f2f2f2f</color>
+  <color name="system_neutral_100">#3f3f3f3f</color>
+  <color name="system_neutral_200">#4f4f4f4f</color>
+  <color name="system_neutral_300">#5f5f5f5f</color>
+  <color name="system_neutral_400">#6f6f6f6f</color>
+  <color name="system_neutral_500">#7f7f7f7f</color>
+  <color name="system_neutral_600">#8f8f8f8f</color>
+  <color name="system_neutral_700">#9f9f9f9f</color>
+  <color name="system_neutral_800">#afafafaf</color>
+  <color name="system_neutral_900">#bfbfbfbf</color>
+  <color name="system_neutral_1000">#cfcfcfcf</color>
+</resources>
diff --git a/core/res/remote_color_resources_res/values/public.xml b/core/res/remote_color_resources_res/values/public.xml
new file mode 100644
index 0000000..e628f09
--- /dev/null
+++ b/core/res/remote_color_resources_res/values/public.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+  <public-group type="color" first-id="0x0106001d">
+    <public name="system_primary_0" />
+    <public name="system_primary_50" />
+    <public name="system_primary_100" />
+    <public name="system_primary_200" />
+    <public name="system_primary_300" />
+    <public name="system_primary_400" />
+    <public name="system_primary_500" />
+    <public name="system_primary_600" />
+    <public name="system_primary_700" />
+    <public name="system_primary_800" />
+    <public name="system_primary_900" />
+    <public name="system_primary_1000" />
+    <public name="system_secondary_0" />
+    <public name="system_secondary_50" />
+    <public name="system_secondary_100" />
+    <public name="system_secondary_200" />
+    <public name="system_secondary_300" />
+    <public name="system_secondary_400" />
+    <public name="system_secondary_500" />
+    <public name="system_secondary_600" />
+    <public name="system_secondary_700" />
+    <public name="system_secondary_800" />
+    <public name="system_secondary_900" />
+    <public name="system_secondary_1000" />
+    <public name="system_neutral_0" />
+    <public name="system_neutral_50" />
+    <public name="system_neutral_100" />
+    <public name="system_neutral_200" />
+    <public name="system_neutral_300" />
+    <public name="system_neutral_400" />
+    <public name="system_neutral_500" />
+    <public name="system_neutral_600" />
+    <public name="system_neutral_700" />
+    <public name="system_neutral_800" />
+    <public name="system_neutral_900" />
+    <public name="system_neutral_1000" />
+  </public-group>
+</resources>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view.xml b/core/res/res/color/text_color_primary_device_default_dark.xml
similarity index 66%
copy from packages/SystemUI/res/layout/udfps_animation_view.xml
copy to core/res/res/color/text_color_primary_device_default_dark.xml
index 380dd85..90d6b07 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view.xml
+++ b/core/res/res/color/text_color_primary_device_default_dark.xml
@@ -14,8 +14,10 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/udfps_animation_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"/>
+<!-- Please see primary_text_material_dark.xml -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:alpha="?attr/disabledAlpha"
+          android:color="@color/system_primary_50"/>
+    <item android:color="@color/system_primary_50"/>
+</selector>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view.xml b/core/res/res/color/text_color_primary_device_default_light.xml
similarity index 66%
copy from packages/SystemUI/res/layout/udfps_animation_view.xml
copy to core/res/res/color/text_color_primary_device_default_light.xml
index 380dd85..bdc4fa9 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view.xml
+++ b/core/res/res/color/text_color_primary_device_default_light.xml
@@ -14,8 +14,10 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/udfps_animation_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"/>
+<!-- Please see primary_text_material_light.xml -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:alpha="?attr/disabledAlpha"
+          android:color="@color/system_primary_900"/>
+    <item android:color="@color/system_primary_900"/>
+</selector>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view.xml b/core/res/res/color/text_color_secondary_device_default_dark.xml
similarity index 66%
copy from packages/SystemUI/res/layout/udfps_animation_view.xml
copy to core/res/res/color/text_color_secondary_device_default_dark.xml
index 380dd85..799636ad 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view.xml
+++ b/core/res/res/color/text_color_secondary_device_default_dark.xml
@@ -14,8 +14,10 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/udfps_animation_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"/>
+<!-- Please see secondary_text_material_dark.xml -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:alpha="?attr/disabledAlpha"
+          android:color="@color/system_primary_200"/>
+    <item android:color="@color/system_primary_200"/>
+</selector>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view.xml b/core/res/res/color/text_color_secondary_device_default_light.xml
similarity index 66%
copy from packages/SystemUI/res/layout/udfps_animation_view.xml
copy to core/res/res/color/text_color_secondary_device_default_light.xml
index 380dd85..4793bb8 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view.xml
+++ b/core/res/res/color/text_color_secondary_device_default_light.xml
@@ -14,8 +14,10 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/udfps_animation_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"/>
+<!-- Please see secondary_text_material_light.xml -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:alpha="?attr/disabledAlpha"
+          android:color="@color/system_primary_700"/>
+    <item android:color="@color/system_primary_700"/>
+</selector>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view.xml b/core/res/res/color/text_color_tertiary_device_default_dark.xml
similarity index 66%
copy from packages/SystemUI/res/layout/udfps_animation_view.xml
copy to core/res/res/color/text_color_tertiary_device_default_dark.xml
index 380dd85..c828631 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view.xml
+++ b/core/res/res/color/text_color_tertiary_device_default_dark.xml
@@ -14,8 +14,10 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/udfps_animation_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"/>
+<!-- Please see tertiary_text_material_dark.xml -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:alpha="?attr/disabledAlpha"
+          android:color="@color/system_primary_400"/>
+    <item android:color="@color/system_primary_400"/>
+</selector>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view.xml b/core/res/res/color/text_color_tertiary_device_default_light.xml
similarity index 66%
copy from packages/SystemUI/res/layout/udfps_animation_view.xml
copy to core/res/res/color/text_color_tertiary_device_default_light.xml
index 380dd85..82c420a 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view.xml
+++ b/core/res/res/color/text_color_tertiary_device_default_light.xml
@@ -14,8 +14,10 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/udfps_animation_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"/>
+<!-- Please see tertiary_text_material_light.xml -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:alpha="?attr/disabledAlpha"
+          android:color="@color/system_primary_500"/>
+    <item android:color="@color/system_primary_500"/>
+</selector>
diff --git a/core/res/res/drawable/conversation_unread_bg.xml b/core/res/res/drawable/expand_button_pill_bg.xml
similarity index 90%
rename from core/res/res/drawable/conversation_unread_bg.xml
rename to core/res/res/drawable/expand_button_pill_bg.xml
index d3e00cf..f95044a 100644
--- a/core/res/res/drawable/conversation_unread_bg.xml
+++ b/core/res/res/drawable/expand_button_pill_bg.xml
@@ -14,6 +14,6 @@
   ~ limitations under the License.
   -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <corners android:radius="20sp" />
+    <corners android:radius="@dimen/notification_expand_button_pill_height" />
     <solid android:color="@android:color/white" />
 </shape>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_collapse_notification.xml b/core/res/res/drawable/ic_collapse_notification.xml
index ca4f0ed..a06ec9f 100644
--- a/core/res/res/drawable/ic_collapse_notification.xml
+++ b/core/res/res/drawable/ic_collapse_notification.xml
@@ -21,8 +21,5 @@
     android:viewportHeight="24.0">
     <path
         android:fillColor="#FF000000"
-        android:pathData="M18.59,16.41L20.0,15.0l-8.0,-8.0 -8.0,8.0 1.41,1.41L12.0,9.83"/>
-    <path
-        android:pathData="M0 0h24v24H0V0z"
-        android:fillColor="#00000000"/>
+        android:pathData="M18.59,15.41L20.0,14.0l-8.0,-8.0 -8.0,8.0 1.41,1.41L12.0,8.83"/>
 </vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_expand_notification.xml b/core/res/res/drawable/ic_expand_notification.xml
index a080ce4..160a9c2 100644
--- a/core/res/res/drawable/ic_expand_notification.xml
+++ b/core/res/res/drawable/ic_expand_notification.xml
@@ -21,8 +21,5 @@
     android:viewportHeight="24.0">
     <path
         android:fillColor="#FF000000"
-        android:pathData="M5.41,7.59L4.0,9.0l8.0,8.0 8.0,-8.0 -1.41,-1.41L12.0,14.17"/>
-    <path
-        android:pathData="M24 24H0V0h24v24z"
-        android:fillColor="#00000000"/>
+        android:pathData="M5.41,8.59L4.0,10.0l8.0,8.0 8.0,-8.0 -1.41,-1.41L12.0,15.17"/>
 </vector>
\ No newline at end of file
diff --git a/core/res/res/layout/notification_expand_button.xml b/core/res/res/layout/notification_expand_button.xml
new file mode 100644
index 0000000..f92e6d6
--- /dev/null
+++ b/core/res/res/layout/notification_expand_button.xml
@@ -0,0 +1,56 @@
+<?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
+  -->
+
+<com.android.internal.widget.NotificationExpandButton
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/expand_button"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="top|end"
+    android:contentDescription="@string/expand_button_content_description_collapsed"
+    android:padding="16dp"
+    android:visibility="gone"
+    >
+
+    <LinearLayout
+        android:id="@+id/expand_button_pill"
+        android:layout_width="wrap_content"
+        android:layout_height="@dimen/notification_expand_button_pill_height"
+        android:orientation="horizontal"
+        android:background="@drawable/expand_button_pill_bg"
+        >
+
+        <TextView
+            android:id="@+id/expand_button_number"
+            android:layout_width="wrap_content"
+            android:layout_height="@dimen/notification_expand_button_pill_height"
+            android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info"
+            android:gravity="center_vertical"
+            android:paddingLeft="8dp"
+            />
+
+        <ImageView
+            android:id="@+id/expand_button_icon"
+            android:layout_width="@dimen/notification_expand_button_pill_height"
+            android:layout_height="@dimen/notification_expand_button_pill_height"
+            android:padding="2dp"
+            android:scaleType="fitCenter"
+            android:importantForAccessibility="no"
+            />
+
+    </LinearLayout>
+
+</com.android.internal.widget.NotificationExpandButton>
diff --git a/core/res/res/layout/notification_template_conversation_header.xml b/core/res/res/layout/notification_template_conversation_header.xml
index 302a388..e01d803 100644
--- a/core/res/res/layout/notification_template_conversation_header.xml
+++ b/core/res/res/layout/notification_template_conversation_header.xml
@@ -99,13 +99,26 @@
         android:visibility="gone"
         />
 
+    <TextView
+        android:id="@+id/verification_divider"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info"
+        android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
+        android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin"
+        android:text="@string/notification_header_divider_symbol"
+        android:layout_gravity="center"
+        android:paddingTop="1sp"
+        android:singleLine="true"
+        android:visibility="gone"
+        />
+
     <ImageView
         android:id="@+id/verification_icon"
         android:layout_width="@dimen/notification_verification_icon_size"
         android:layout_height="@dimen/notification_verification_icon_size"
         android:layout_gravity="center"
         android:layout_marginStart="4dp"
-        android:contentDescription="@string/notification_alerted_content_description"
         android:paddingTop="2dp"
         android:scaleType="fitCenter"
         android:src="@drawable/ic_notifications_alerted"
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index 1de1d04..81a79c5 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -30,7 +30,8 @@
         android:id="@+id/left_icon"
         android:layout_width="@dimen/notification_left_icon_size"
         android:layout_height="@dimen/notification_left_icon_size"
-        android:layout_gravity="center_vertical|start"
+        android:layout_alignParentStart="true"
+        android:layout_centerVertical="true"
         android:layout_marginStart="@dimen/notification_left_icon_start"
         android:background="@drawable/notification_large_icon_outline"
         android:clipToOutline="true"
@@ -43,7 +44,8 @@
         android:id="@+id/icon"
         android:layout_width="@dimen/notification_icon_circle_size"
         android:layout_height="@dimen/notification_icon_circle_size"
-        android:layout_gravity="center_vertical|start"
+        android:layout_alignParentStart="true"
+        android:layout_centerVertical="true"
         android:layout_marginStart="@dimen/notification_icon_circle_start"
         android:background="@drawable/notification_icon_circle"
         android:padding="@dimen/notification_icon_circle_padding"
@@ -55,10 +57,12 @@
         android:id="@+id/notification_top_line"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
-        android:layout_gravity="center_vertical"
+        android:layout_alignParentStart="true"
+        android:layout_centerVertical="true"
+        android:layout_toStartOf="@id/expand_button"
+        android:layout_alignWithParentIfMissing="true"
         android:clipChildren="false"
         android:gravity="center_vertical"
-        android:paddingEnd="@dimen/notification_heading_margin_end"
         android:paddingStart="@dimen/notification_content_margin_start"
         android:theme="@style/Theme.DeviceDefault.Notification"
         >
@@ -71,19 +75,15 @@
         android:id="@+id/alternate_expand_target"
         android:layout_width="@dimen/notification_content_margin_start"
         android:layout_height="match_parent"
-        android:layout_gravity="start"
+        android:layout_alignParentStart="true"
         android:importantForAccessibility="no"
         />
 
-    <com.android.internal.widget.NotificationExpandButton
-        android:id="@+id/expand_button"
-        android:layout_width="@dimen/notification_header_expand_icon_size"
-        android:layout_height="@dimen/notification_header_expand_icon_size"
-        android:layout_gravity="center_vertical|end"
-        android:contentDescription="@string/expand_button_content_description_collapsed"
-        android:paddingTop="@dimen/notification_expand_button_padding_top"
-        android:scaleType="center"
-        android:visibility="gone"
+    <include layout="@layout/notification_expand_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentEnd="true"
+        android:layout_centerVertical="true"
         />
 
 </NotificationHeaderView>
diff --git a/core/res/res/layout/notification_template_material_base.xml b/core/res/res/layout/notification_template_material_base.xml
index d79cb74..bad9a6b 100644
--- a/core/res/res/layout/notification_template_material_base.xml
+++ b/core/res/res/layout/notification_template_material_base.xml
@@ -74,14 +74,10 @@
         android:layout_height="match_parent"
         android:layout_gravity="end">
 
-        <com.android.internal.widget.NotificationExpandButton
-            android:id="@+id/expand_button"
-            android:layout_width="@dimen/notification_header_expand_icon_size"
-            android:layout_height="@dimen/notification_header_expand_icon_size"
+        <include layout="@layout/notification_expand_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
             android:layout_gravity="center_vertical|end"
-            android:contentDescription="@string/expand_button_content_description_collapsed"
-            android:paddingTop="@dimen/notification_expand_button_padding_top"
-            android:scaleType="center"
             />
 
     </FrameLayout>
@@ -91,26 +87,11 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
-        android:layout_marginBottom="@dimen/notification_headerless_margin_minimum"
-        android:layout_marginTop="@dimen/notification_headerless_margin_minimum"
+        android:layout_marginBottom="@dimen/notification_headerless_margin_twoline"
+        android:layout_marginTop="@dimen/notification_headerless_margin_twoline"
         android:orientation="vertical"
         >
 
-        <!--
-        This invisible FrameLayout is here as a collapsible padding.  Having a layout_weight=1 is
-        what causes this view (and it's counterpart at the opposite end) to collapse before the
-        actual content views do.
-        This pair of 10dp collapsible paddings (plus the 16dp fixed margins) allow us to support
-        headerless notifications of 1-3 lines (where each line is 20dp tall) where the 1-line
-        variant is 56dp and the 2- and 3-line variants are both 76dp.
-        -->
-        <FrameLayout
-            android:id="@+id/notification_headerless_margin_extra_top"
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/notification_headerless_margin_extra"
-            android:layout_weight="1"
-            />
-
         <!-- extends ViewGroup -->
         <NotificationTopLineView
             android:id="@+id/notification_top_line"
@@ -153,12 +134,20 @@
             android:orientation="vertical"
             >
 
-            <include
-                layout="@layout/notification_template_text"
+            <com.android.internal.widget.NotificationVanishingFrameLayout
                 android:layout_width="match_parent"
                 android:layout_height="@dimen/notification_headerless_line_height"
-                android:layout_marginTop="0dp"
-                />
+                >
+                <!-- This is the simplest way to keep this text vertically centered without using
+                 gravity="center_vertical" which causes jumpiness in expansion animations. -->
+                <include
+                    layout="@layout/notification_template_text"
+                    android:layout_width="match_parent"
+                    android:layout_height="@dimen/notification_text_height"
+                    android:layout_gravity="center_vertical"
+                    android:layout_marginTop="0dp"
+                    />
+            </com.android.internal.widget.NotificationVanishingFrameLayout>
 
             <include
                 layout="@layout/notification_template_progress"
@@ -168,21 +157,6 @@
 
         </LinearLayout>
 
-        <!--
-        This invisible FrameLayout is here as a collapsible padding.  Having a layout_weight=1 is
-        what causes this view (and it's counterpart at the opposite end) to collapse before the
-        actual content views do.
-        This pair of 10dp collapsible paddings (plus the 16dp fixed margins) allow us to support
-        headerless notifications of 1-3 lines (where each line is 20dp tall) where the 1-line
-        variant is 56dp and the 2- and 3-line variants are both 76dp.
-        -->
-        <FrameLayout
-            android:id="@+id/notification_headerless_margin_extra_bottom"
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/notification_headerless_margin_extra"
-            android:layout_weight="1"
-            />
-
     </LinearLayout>
 
 </com.android.internal.widget.NotificationMaxHeightFrameLayout>
diff --git a/core/res/res/layout/notification_template_material_call.xml b/core/res/res/layout/notification_template_material_call.xml
index 471d874..7b52ec3 100644
--- a/core/res/res/layout/notification_template_material_call.xml
+++ b/core/res/res/layout/notification_template_material_call.xml
@@ -72,15 +72,10 @@
             </LinearLayout>
 
             <!-- TODO(b/179178086): remove padding from main column when this is visible -->
-            <com.android.internal.widget.NotificationExpandButton
-                android:id="@+id/expand_button"
-                android:layout_width="@dimen/notification_header_expand_icon_size"
-                android:layout_height="@dimen/notification_header_expand_icon_size"
+            <include layout="@layout/notification_expand_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
                 android:layout_gravity="top|end"
-                android:contentDescription="@string/expand_button_content_description_collapsed"
-                android:paddingTop="@dimen/notification_expand_button_padding_top"
-                android:scaleType="center"
-                android:visibility="gone"
                 />
 
         </LinearLayout>
diff --git a/core/res/res/layout/notification_template_material_conversation.xml b/core/res/res/layout/notification_template_material_conversation.xml
index f3aa540..42fb4a2 100644
--- a/core/res/res/layout/notification_template_material_conversation.xml
+++ b/core/res/res/layout/notification_template_material_conversation.xml
@@ -104,11 +104,10 @@
         <LinearLayout
             android:id="@+id/expand_button_touch_container"
             android:layout_width="wrap_content"
-            android:layout_height="@dimen/conversation_expand_button_size"
-            android:paddingStart="@dimen/conversation_expand_button_side_margin"
+            android:layout_height="@dimen/conversation_expand_button_height"
             android:orientation="horizontal"
             android:layout_gravity="end|top"
-            android:paddingEnd="@dimen/conversation_expand_button_side_margin"
+            android:paddingEnd="0dp"
             android:clipToPadding="false"
             android:clipChildren="false"
             >
@@ -118,34 +117,16 @@
                 android:forceHasOverlappingRendering="false"
                 android:layout_width="40dp"
                 android:layout_height="40dp"
-                android:layout_marginEnd="11dp"
+                android:layout_marginStart="@dimen/conversation_image_start_margin"
                 android:spacing="0dp"
                 android:layout_gravity="center"
                 android:clipToPadding="false"
                 android:clipChildren="false"
                 />
-            <!-- Unread Count -->
-            <TextView
-                android:id="@+id/conversation_unread_count"
-                android:layout_width="33sp"
-                android:layout_height="wrap_content"
-                android:layout_marginEnd="11dp"
-                android:layout_gravity="center"
-                android:gravity="center"
-                android:padding="2dp"
-                android:visibility="gone"
-                android:textAppearance="@style/TextAppearance.DeviceDefault.Notification"
-                android:textColor="#FFFFFF"
-                android:textSize="12sp"
-                android:background="@drawable/conversation_unread_bg"
-                />
-            <com.android.internal.widget.NotificationExpandButton
-                android:id="@+id/expand_button"
+            <include layout="@layout/notification_expand_button"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_gravity="center"
-                android:drawable="@drawable/ic_expand_notification"
-                android:contentDescription="@string/expand_button_content_description_collapsed"
                 />
         </LinearLayout>
     </FrameLayout>
diff --git a/core/res/res/layout/splash_screen_view.xml b/core/res/res/layout/splash_screen_view.xml
index 513da5e..e6d724f 100644
--- a/core/res/res/layout/splash_screen_view.xml
+++ b/core/res/res/layout/splash_screen_view.xml
@@ -21,14 +21,16 @@
     android:orientation="vertical">
 
     <View android:id="@+id/splashscreen_icon_view"
-    android:layout_height="wrap_content"
-    android:layout_width="wrap_content"
-    android:layout_gravity="center"/>
+          android:layout_height="wrap_content"
+          android:layout_width="wrap_content"
+          android:layout_gravity="center"
+          android:contentDescription="@string/splash_screen_view_icon_description"/>
 
     <View android:id="@+id/splashscreen_branding_view"
           android:layout_height="wrap_content"
           android:layout_width="wrap_content"
           android:layout_gravity="center_horizontal|bottom"
-          android:layout_marginBottom="60dp"/>
+          android:layout_marginBottom="60dp"
+          android:contentDescription="@string/splash_screen_view_branding_description"/>
 
 </android.window.SplashScreenView>
\ No newline at end of file
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index aa4baf3..4b591bf 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Kan nie meer gesig herken nie. Probeer weer."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Te eenders. Verander asseblief jou pose."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Draai jou kop \'n bietjie minder."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Draai jou kop \'n bietjie minder."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Draai jou kop \'n bietjie minder."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Verwyder enigiets wat jou gesig versteek."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Maak die bokant van jou skerm skoon, insluitend die swart balk"</string>
@@ -1667,7 +1668,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Gebruik kortpad"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Kleuromkering"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Kleurkorreksie"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Verminder helderheid"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Het volumesleutels ingehou. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aangeskakel."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Het volumesleutels ingehou. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> is afgeskakel"</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Druk en hou albei volumesleutels drie sekondes lank om <xliff:g id="SERVICE_NAME">%1$s</xliff:g> te gebruik"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS-versoek is na video-oproep toe verander"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS-versoek is na USSD-versoek toe verander"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Na nuwe SS-versoek toe verander"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Uitvissingwaarskuwing"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Werkprofiel"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Kennisgewing gegee"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Vou uit"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Om voort te gaan, moet &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; toegang tot jou toestel se kamera hê."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Skakel aan"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensorprivaatheid"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 9b11350..a43b29a 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"ከእንግዲህ ፊትን ለይቶ ማወቅ አይችልም። እንደገና ይሞክሩ።"</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"በጣም ይመሳሰላል፣ እባክዎ የእርስዎን ፎቶ አነሳስ ይለውጡ"</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ጭንቅላትዎን ትንሽ ብቻ ያዙሩት።"</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"ጭንቅላትዎን ትንሽ ብቻ ያዙሩት።"</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ጭንቅላትዎን ትንሽ ብቻ ያዙሩት።"</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"የእርስዎን ፊት የሚደብቀውን ሁሉንም ነገር በማስወገድ ላይ"</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"የማያ ገጽዎን አናት ያጽዱት፣ ጥቁር አሞሌውን ጨምሮ"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ብሩህነትን ይቀንሱ"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ን ለመጠቀም ለሦስት ሰከንዶች ሁለቱንም የድምፅ ቁልፎች ተጭነው ይያዙ"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"የSS ጥያቄ ወደ የቪዲዮ ጥሪ ተለውጧል"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"የSS ጥያቄ ወደ የUSSD ጥያቄ ተለውጧል"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"ወደ አዲስ የSS ጥያቄ ተለውጧል"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"የማስገር ማንቂያ"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"የስራ መገለጫ"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"ነቅተዋል"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"ዘርጋ"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"ለመቀጠል፣ &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; የመሣሪያዎን ካሜራ መድረስ ይፈልጋል።"</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"አብራ"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"ዳሳሽ ግላዊነት"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index bbf30fe..3990bab 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -618,7 +618,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"لم يعُد يمكن التعرّف على الوجه. حاول مرة أخرى."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"الوجه مشابه جدًا، يُرجى تغيير وضعيتك."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"حرّك رأسك قليلاً نحو الأمام مباشرة."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"حرّك رأسك قليلاً نحو الأمام مباشرة."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"حرّك رأسك قليلاً نحو الوسط."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"عليك بإزالة أي شيء يُخفي وجهك."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"يُرجى تنظيف الجزء العلوي من الشاشة، بما في ذلك الشريط الأسود."</string>
@@ -1755,7 +1756,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"تقليل السطوع"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"اضغط مع الاستمرار على مفتاحي مستوى الصوت لمدة 3 ثوانٍ لاستخدام <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
@@ -1995,8 +1997,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"‏تم تغيير طلب SS إلى مكالمة فيديو."</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"‏تم تغيير طلب SS إلى طلب USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"‏تم التغيير إلى طلب SS الجديد."</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"تنبيه بشأن تصيّد احتيالي"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"الملف الشخصي للعمل"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"تمّ تفعيل التنبيه"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"توسيع"</string>
@@ -2356,4 +2357,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"‏للمتابعة، يحتاج تطبيق &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; إلى الوصول إلى كاميرا الجهاز."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"تفعيل"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"الخصوصية في جهاز الاستشعار"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index e4f657f..28af8a3 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"মুখমণ্ডল আৰু চিনাক্ত কৰিব নোৱাৰি। আকৌ চেষ্টা কৰক।"</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"একে ধৰণৰ হৈছে, অনুগ্ৰহ কৰি আপোনাৰ প’জটো সলনি কৰক।"</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"আপোনাৰ মূৰটো সামান্য কমকৈ ঘূৰাওক।"</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"আপোনাৰ মূৰটো সামান্য কমকৈ ঘূৰাওক।"</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"আপোনাৰ মূৰটো সামান্য কমকৈ ঘূৰাওক।"</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"আপোনাৰ মুখখন ঢাকি ৰখা বস্তুবোৰ আঁতৰাওক।"</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ক’লা বাৰডালকে ধৰি আপোনাৰ স্ক্রীণৰ ওপৰৰ অংশ চাফা কৰক"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"উজ্জ্বলতা কমাওক"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ব্যৱহাৰ কৰিবলৈ দুয়োটা ভলিউম বুটাম তিনি ছেকেণ্ডৰ বাবে হেঁচি ৰাখক"</string>
@@ -2219,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"অব্যাহত ৰাখিবলৈ &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt;এ আপোনাৰ ডিভাইচৰ কেমেৰা এক্সেছ কৰাৰ আৱশ্যক।"</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"অন কৰক"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"ছেন্সৰ সম্পৰ্কীয় গোপনীয়তাৰ নীতি"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 549784d..8459403 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Üzü artıq tanımaq olmur. Yenidən cəhd edin."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Digəri ilə oxşardır, pozanızı dəyişin."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Başınızı bir az döndərin."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Başınızı bir az döndərin."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Başınızı bir az döndərin."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Üzünüzü gizlədən maneələri kənarlaşdırın."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Qara panel daxil olmaqla, ekranın yuxarısını təmizləyin"</string>
@@ -1667,7 +1668,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Qısayol İstifadə edin"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Rəng İnversiyası"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Rəng korreksiyası"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Parlaqlığı Azaldın"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Səs səviyyəsi düymələrinə basıb saxlayın. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktiv edildi."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Səs səviyyəsi düymələrinə basılaraq saxlanıb. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> deaktiv edilib."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> istifadə etmək üçün hər iki səs düyməsini üç saniyə basıb saxlayın"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS sorğusu video zəngə dəyişdirildi"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS sorğusu USSD sorğusuna dəyişdirildi"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Yeni SS sorğusuna dəyişdirildi"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Fişinq siqnalı"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"İş profili"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Xəbərdarlıq edildi"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Genişləndirin"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Davam etmək üçün &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; tətbiqi cihazın kamerasına giriş tələb edir."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Aktiv edin"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensor Məxfiliyi"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 5709e3d..a7f6433 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -609,7 +609,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Više ne može da se prepozna lice. Probajte ponovo."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Previše je slično, promenite pozu."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Malo manje pomerite glavu."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Malo manje pomerite glavu."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Malo manje pomerite glavu."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Uklonite sve što vam zaklanja lice."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Očistite gornji deo ekrana, uključujući crnu traku"</string>
@@ -1689,7 +1690,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Koristi prečicu"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Inverzija boja"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Korekcija boja"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Smanjite osvetljenost"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Držali ste tastere za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je uključena."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Držali ste tastere za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je isključena."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Pritisnite i zadržite oba tastera za jačinu zvuka tri sekunde da biste koristili <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2253,4 +2255,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"&lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; zahteva pristup kameri uređaja radi nastavljanja."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Uključi"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privatnost senzora"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 880c986..1022cef 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -612,7 +612,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Не ўдаецца распазнаць твар. Паўтарыце спробу."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Не бачна розніцы. Памяняйце позу."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Вы занадта моцна павярнулі галаву."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Галава не ў цэнтры."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Вы занадта моцна павярнулі галаву."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Прыміце ўсё, што закрывае ваш твар."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Ачысціце ад бруду верхнюю частку экрана, у тым ліку чорную панэль"</string>
@@ -793,7 +794,7 @@
     <string name="eventTypeAnniversary" msgid="4684702412407916888">"Гадавіна"</string>
     <string name="eventTypeOther" msgid="530671238533887997">"Іншае"</string>
     <string name="emailTypeCustom" msgid="1809435350482181786">"Карыстальніцкая"</string>
-    <string name="emailTypeHome" msgid="1597116303154775999">"Хатні"</string>
+    <string name="emailTypeHome" msgid="1597116303154775999">"Асабістая"</string>
     <string name="emailTypeWork" msgid="2020095414401882111">"Працоўная"</string>
     <string name="emailTypeOther" msgid="5131130857030897465">"Іншая"</string>
     <string name="emailTypeMobile" msgid="787155077375364230">"Мабільны"</string>
@@ -1711,7 +1712,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Паменшыць яркасць"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Каб карыстацца сэрвісам \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\", націсніце і ўтрымлівайце на працягу трох секунд абедзве клавішы гучнасці"</string>
@@ -1933,8 +1935,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS-запыт заменены на відэавыклік"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS-запыт заменены на USSD-запыт"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Зроблена замена на новы SS-запыт"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Абвестка пра фішынг"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Працоўны профіль"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"З гукам"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Разгарнуць"</string>
@@ -2288,4 +2289,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Каб працягнуць, дайце праграме &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; доступ да камеры прылады."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Уключыць"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Прыватнасць інфармацыі з датчыка"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 2ed363f..ef20bad 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Лицето не бе разпознато. Опитайте отново."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Позата ви е сходна с предишна. Моля, променете я."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Не завъртайте главата си толкова много."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Не завъртайте главата си толкова много."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Не завъртайте главата си толкова много."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Премахнете всичко, което закрива лицето ви."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Почистете горната част на екрана си, включително черната лента"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Намаляване на яркостта"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"За да използвате <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, натиснете двата бутона за силата на звука и ги задръжте за 3 секунди"</string>
@@ -2219,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"За да продължите, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; се нуждае от достъп до камерата на устройството ви."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Включване"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Поверителност на сензорните данни"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index dd38e9a..0e30c04 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"আর মুখ চিনতে পারবেন না। আবার চেষ্টা করুন।"</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"একই ধরনের দেখতে, একটু অন্যদিকে ঘুরে দাঁড়ান।"</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"আপনার মাথাটি নিচের দিকে সামান্য নামান।"</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"আপনার মাথাটি নিচের দিকে সামান্য নামান।"</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"আপনার মাথাটি সামান্য ঘোরান।"</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"আপনার ফেসকে আড়াল করে এমন সব কিছু সরিয়ে দিন।"</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ব্ল্যাক বার সহ আপনার স্ক্রিনের উপরের অংশ মুছে ফেলুন"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"উজ্জ্বলতা কমান"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ব্যবহার করতে ভলিউম কী বোতাম ৩ সেকেন্ডের জন্য চেপে ধরে রাখুন"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS অনুরোধ ভিডিও কলে পরিবর্তন করা হয়েছে"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS অনুরোধ USSD অনুরোধে পরিবর্তন করা হয়েছে"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"নতুন SS অনুরোধে পরিবর্তন করা হয়েছে"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ফিশিংয়ের সতর্কতা"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"কর্মস্থলের প্রোফাইল"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"সতর্ক করা হয়েছে"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"বড় করুন"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"চালিয়ে যেতে, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; আপনার ডিভাইসের ক্যামেরা অ্যাক্সেস করতে চায়।"</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"চালু করুন"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"সেন্সর গোপনীয়তা"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index d5b10d5..77b64b5 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -609,7 +609,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Više nije moguće prepoznati lice. Pokušajte opet."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Previše slično, promijenite položaj."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Malo manje zakrenite glavu."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Malo manje zakrenite glavu."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Malo manje zakrenite glavu."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Uklonite prepreke koje blokiraju vaše lice."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Očistite vrh ekrana, uključujući crnu traku"</string>
@@ -689,7 +690,7 @@
     <string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"pokrenuti korištenje odobrenja za pregled"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Dozvoljava vlasniku da pokrene korištenje odobrenja za aplikaciju. Ne bi trebalo biti potrebno za obične aplikacije."</string>
     <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"pristup podacima senzora velikom brzinom uzorkovanja"</string>
-    <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Dozvoljava aplikaciji da uzorkuje podatke senzora većom brzinom od 200 Hz"</string>
+    <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Dozvoljava aplikaciji da uzorkuje podatke senzora brzinom većom od 200 Hz"</string>
     <string name="policylab_limitPassword" msgid="4851829918814422199">"Postavljanje pravila za lozinke"</string>
     <string name="policydesc_limitPassword" msgid="4105491021115793793">"Kontrolira dužinu i znakove koji su dozvoljeni u lozinkama za zaključavanje ekrana i PIN-ovima."</string>
     <string name="policylab_watchLogin" msgid="7599669460083719504">"Prati pokušaje otključavanja ekrana"</string>
@@ -1689,7 +1690,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Koristi prečicu"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Inverzija boja"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Ispravka boja"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Smanjenje osvjetljenja"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Držali ste tipke za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je uključena."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Držali ste tipke za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je isključena."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Pritisnite obje tipke za podešavanje jačine zvuka i držite ih pritisnutim tri sekunde da koristite uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2253,4 +2255,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Da nastavite, aplikaciji &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; je potreban pristup kameri vašeg uređaja."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Uključi"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privatnost senzora"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 280fe1a..a226ac3 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Ja no es reconeix la teva cara. Torna-ho a provar."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"És massa semblant; canvia de postura."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"No giris tant el cap."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"No inclinis tant el cap."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"No giris tant el cap."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Suprimeix qualsevol cosa que amagui la teva cara."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Neteja la part superior de la pantalla, inclosa la barra negra"</string>
@@ -1667,7 +1668,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utilitza la drecera"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversió de colors"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Correcció de color"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reducció de la brillantor"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"S\'han mantingut premudes les tecles de volum. S\'ha activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"S\'han mantingut premudes les tecles de volum. S\'ha desactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Mantén premudes les dues tecles de volum durant 3 segons per fer servir <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Per continuar, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; necessita accedir a la càmera del dispositiu."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Activa"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privadesa dels sensors"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 091ed83..fdb2ff1 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -612,7 +612,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Obličej už nelze rozpoznat. Zkuste to znovu."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Příliš podobné, změňte výraz."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Natočte hlavu o něco méně."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Natočte hlavu o něco méně."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Natočte hlavu o něco méně."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Odstraňte vše, co vám zakrývá obličej."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Očistěte horní část obrazovky včetně černé části"</string>
@@ -1711,7 +1712,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Použít zkratku"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Převrácení barev"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Oprava barev"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Snížit jas"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Byla podržena tlačítka hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je zapnutá."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Byla podržena tlačítka hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> byla vypnuta."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Chcete-li používat službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, tři sekundy podržte stisknutá obě tlačítka hlasitosti"</string>
@@ -1933,8 +1935,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Požadavek SS byl změněn na videohovor"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Požadavek SS byl změněn na požadavek USSD"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Změněno na nový požadavek SS"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Upozornění na phishing"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Pracovní profil"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Upozorněno"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Rozbalit"</string>
@@ -2288,4 +2289,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Než budete pokračovat, udělte aplikaci &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; přístup k fotoaparátu na zařízení."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Zapnout"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Ochrana soukromí – senzor"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 8e19100..dddc070 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -608,7 +608,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Ansigtet kan ikke længere genkendes. Prøv igen."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Det minder for meget om et andet. Skift stilling."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Du skal ikke dreje hovedet så meget."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Du skal ikke dreje hovedet så meget."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Du skal ikke dreje hovedet så meget."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Hvis noget skjuler dit ansigt, skal du fjerne det."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Rengør toppen af din skærm, inkl. den sorte bjælke"</string>
@@ -1669,7 +1670,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Brug genvej"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Ombytning af farver"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Korriger farve"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reducer lysstyrken"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Lydstyrkeknapperne blev holdt nede. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er aktiveret."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Lydstyrkeknapperne blev holdt nede. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er deaktiveret."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Hold begge lydstyrkeknapper nede i tre sekunder for at bruge <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1873,8 +1875,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS-anmodningen blev ændret til et videoopkald"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS-anmodningen blev ændret til en USSD-anmodning"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Ændret til en SS-anmodning"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Phishingadvarsel"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Arbejdsprofil"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Underrettet"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Udvid"</string>
@@ -2222,4 +2223,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"&lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; skal have adgang til din enheds kamera, før den kan fortsætte."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Aktivér"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Beskyttelse af sensoroplysninger"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index d9710e6..472f1d2 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Gesicht wird nicht mehr erkannt. Erneut versuchen."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Zu ähnlich. Bitte dreh deinen Kopf etwas."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Dreh den Kopf etwas weniger zur Seite."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Neig den Kopf etwas weniger stark."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Neig den Kopf etwas weniger stark."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Entferne alles, was dein Gesicht verdeckt."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Reinige den oberen Teil deines Bildschirms, einschließlich der schwarzen Leiste"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Helligkeit verringern"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Halten Sie beide Lautstärketasten drei Sekunden lang gedrückt, um <xliff:g id="SERVICE_NAME">%1$s</xliff:g> zu verwenden"</string>
@@ -2219,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Zum Fortfahren benötigt &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; Zugriff auf die Kamera deines Geräts."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Aktivieren"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Datenschutz für Sensoren"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 358a1f1..22b3401 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Αδύνατη η αναγνώριση του προσώπου. Επανάληψη."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Πολύ παρόμοιο, αλλάξτε την πόζα σας."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Στρέψτε λιγότερο το κεφάλι σας."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Στρέψτε λιγότερο το κεφάλι σας."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Στρέψτε λιγότερο το κεφάλι σας."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Απομακρύνετε οτιδήποτε κρύβει το πρόσωπό σας."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Καθαρίστε το επάνω μέρος της οθόνης σας, συμπεριλαμβανομένης της μαύρης γραμμής"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Μείωση φωτεινότητας"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Πατήστε παρατεταμένα και τα δύο κουμπιά έντασης ήχου για τρία δευτερόλεπτα, ώστε να χρησιμοποιήσετε την υπηρεσία <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Το αίτημα SS τροποποιήθηκε σε βιντεοκλήση"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Το αίτημα SS τροποποιήθηκε σε αίτημα USSD"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Τροποποιήθηκε σε νέο αίτημα SS"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Ειδοποίηση ηλεκτρονικού ψαρέματος (phishing)"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Προφίλ εργασίας"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Ειδοποιήθηκε"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Ανάπτυξη"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Για να συνεχίσετε, η εφαρμογή &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; χρειάζεται πρόσβαση στην κάμερα της συσκευής σας."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Ενεργοποίηση"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Απόρρητο αισθητήρα"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 058ae77..f2cbb75 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -606,7 +606,7 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"No longer able to recognise face. Try again."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Too similar, please change your pose."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Turn your head a little less."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Turn your head a little less."</string>
+    <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Tilt your head a little less."</string>
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Turn your head a little less."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Remove anything hiding your face."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Clean the top of your screen, including the black bar"</string>
@@ -1667,7 +1667,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Use Shortcut"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Colour Inversion"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Colour correction"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduce Brightness"</string>
+    <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Reduce brightness"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2219,6 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"To continue, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; needs access to your device’s camera."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Turn on"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensor privacy"</string>
+    <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Application icon"</string>
+    <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Application branding image"</string>
 </resources>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index d91b3d0..f440c8a 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -606,7 +606,7 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"No longer able to recognise face. Try again."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Too similar, please change your pose."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Turn your head a little less."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Turn your head a little less."</string>
+    <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Tilt your head a little less."</string>
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Turn your head a little less."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Remove anything hiding your face."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Clean the top of your screen, including the black bar"</string>
@@ -1667,7 +1667,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Use Shortcut"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Colour inversion"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Colour correction"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduce Brightness"</string>
+    <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Reduce brightness"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2219,6 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"To continue, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; needs access to your device’s camera."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Turn on"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensor privacy"</string>
+    <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Application icon"</string>
+    <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Application branding image"</string>
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 60950ee..93881e9 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -606,7 +606,7 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"No longer able to recognise face. Try again."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Too similar, please change your pose."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Turn your head a little less."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Turn your head a little less."</string>
+    <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Tilt your head a little less."</string>
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Turn your head a little less."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Remove anything hiding your face."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Clean the top of your screen, including the black bar"</string>
@@ -1667,7 +1667,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Use Shortcut"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Colour Inversion"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Colour correction"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduce Brightness"</string>
+    <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Reduce brightness"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2219,6 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"To continue, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; needs access to your device’s camera."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Turn on"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensor privacy"</string>
+    <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Application icon"</string>
+    <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Application branding image"</string>
 </resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 1915d45..a7fa30e 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -606,7 +606,7 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"No longer able to recognise face. Try again."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Too similar, please change your pose."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Turn your head a little less."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Turn your head a little less."</string>
+    <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Tilt your head a little less."</string>
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Turn your head a little less."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Remove anything hiding your face."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Clean the top of your screen, including the black bar"</string>
@@ -1667,7 +1667,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Use Shortcut"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Colour Inversion"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Color correction"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduce Brightness"</string>
+    <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Reduce brightness"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2219,6 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"To continue, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; needs access to your device’s camera."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Turn on"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensor privacy"</string>
+    <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Application icon"</string>
+    <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Application branding image"</string>
 </resources>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 0a90aeac..ce9a915 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -606,7 +606,7 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‏‏‎‎‎‏‎‎‎‏‎‎‏‎‏‏‏‎‎‏‏‎‎‏‎‎‎‏‎‎‏‏‏‎‎‏‎‎‏‏‏‎‎‎‏‏‏‏‎‏‏‏‎‎No longer able to recognize face. Try again.‎‏‎‎‏‎"</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‎‏‎‏‎‏‎‏‏‏‎‏‎‎‏‎‏‏‎‎‏‎‎‎‏‏‎‏‎‏‎‏‎‎‎‎‎‎‎‏‎‏‎‏‎‎‎‎‏‎‏‎‎Too similar, please change your pose.‎‏‎‎‏‎"</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‏‏‏‎‎‎‎‎‎‎‎‏‏‎‎‎‎‎‏‎‎‏‏‎‎‎‏‎‏‎‎‎‎‎‎‏‎‏‏‎‎‎‎‎‏‎‎‎‏‏‏‏‎Turn your head a little less.‎‏‎‎‏‎"</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‏‏‏‎‏‎‏‎‎‏‏‎‎‏‏‎‎‎‎‏‏‏‎‎‏‏‎‎‏‏‏‎‏‏‎Turn your head a little less.‎‏‎‎‏‎"</string>
+    <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‏‎‎‎‎‎‏‎‎‏‎‎‎‎‎‎‏‎‎‏‎‏‏‎‎‏‎‏‎‏‎‏‎‏‏‏‎‏‎‏‏‏‏‏‏‏‎‎‎‏‎Tilt your head a little less.‎‏‎‎‏‎"</string>
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‏‎‏‏‎‏‎‏‎‎‏‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‏‎‎‏‏‎‎‏‎Turn your head a little less.‎‏‎‎‏‎"</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‎‎‎‎‏‎‏‏‎‎‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‎‏‎‎‎‎‎‏‎‏‏‏‏‎Remove anything hiding your face.‎‏‎‎‏‎"</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‎‎‎‏‎‎‎‎‎‏‏‏‎‏‎‎‎‏‎‎‎‏‎‏‎‏‎‏‏‎‏‏‏‏‏‎‎‎‎‏‎‏‎‎‎‏‏‏‎‎Clean the top of your screen, including the black bar‎‏‎‎‏‎"</string>
@@ -1667,7 +1667,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‏‏‏‎‏‎‏‏‎‎‎‏‎‎‏‎‎‎‎‎‏‎‏‎‎‎‏‎‎‏‎‏‏‏‎‏‎‎‎‏‏‏‏‎‎‏‎‏‏‏‏‎‎Use Shortcut‎‏‎‎‏‎"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‏‎‎‎‎‏‏‎‎‏‎‏‏‏‎‎‏‏‎‎‏‎‏‎‏‏‎‎‎‎‎‏‎‏‎‏‎‏‏‎‏‏‏‎‏‏‏‏‏‏‎‏‎‏‎‎‎Color Inversion‎‏‎‎‏‎"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‏‏‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‎‏‏‏‏‎‎‎‏‎‎‎‎‎‎‎‏‎‎‎‎‏‏‎‎‎‎‎‎‎‎‏‎‏‎Color Correction‎‏‎‎‏‎"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‏‎‏‏‏‎‎‎‏‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‎‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‎‏‏‎‏‏‎‏‏‎‏‎‎Reduce Brightness‎‏‎‎‏‎"</string>
+    <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‎‏‎‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‏‎‏‏‏‎‎‏‎‏‎‏‏‎‎‏‏‎‎Reduce brightness‎‏‎‎‏‎"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‎‎‎‏‏‎‏‎‏‎‎‏‏‏‏‏‎‏‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‎‏‏‏‎Held volume keys. ‎‏‎‎‏‏‎<xliff:g id="SERVICE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ turned on.‎‏‎‎‏‎"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‏‎‎‏‎‏‎‏‎‎‎‏‎‎‏‏‎‏‎‏‏‎‎‏‏‏‎‎‏‎‏‎‏‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‎‏‏‎Held volume keys. ‎‏‎‎‏‏‎<xliff:g id="SERVICE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ turned off.‎‏‎‎‏‎"</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‏‎‎‎‎‎‏‏‎‏‎‏‎‎‏‏‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‎‏‎‎‏‎‏‏‏‏‎‎‏‎‎Press and hold both volume keys for three seconds to use ‎‏‎‎‏‏‎<xliff:g id="SERVICE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
@@ -2219,4 +2219,6 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‎‎‎‎‎‎‏‏‎‎‎‏‏‏‎‎‎‎‎‏‏‏‏‎‎‏‎‎‎‏‏‎‏‎‎‎‏‏‎‏‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎To continue, &lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP">%s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; needs access to your device’s camera.‎‏‎‎‏‎"</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‏‏‎‏‏‎‎‏‎‎‎‏‎‎‏‏‏‎‏‏‎‎‎‎‏‎‎‎‎‏‏‏‏‏‎‏‎‏‏‏‎‏‎‎‏‏‎‏‎‏‏‏‎Turn on‎‏‎‎‏‎"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‏‎‏‎‏‎‏‏‎‎‏‎‏‏‏‏‏‎‏‎‎‏‎‏‎Sensor Privacy‎‏‎‎‏‎"</string>
+    <string name="splash_screen_view_icon_description" msgid="180638751260598187">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‎‏‏‏‎‎‎‎‎‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‏‏‎‎‎‏‏‏‎‏‏‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎Application icon‎‏‎‎‏‎"</string>
+    <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‎‏‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‎‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‏‏‏‎‎‎‎‎‏‏‎‎‎‏‏‎‎‎‎Application branding image‎‏‎‎‏‎"</string>
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index e81d6d1..01d0c7e 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Ya no se reconoce el rostro. Vuelve a intentarlo."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Es muy similar a la anterior. Haz otra pose."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Gira la cabeza un poco menos."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Gira la cabeza un poco menos."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Gira la cabeza un poco menos."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Quítate cualquier objeto que te cubra el rostro."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Limpia la parte superior de la pantalla, incluida la barra negra"</string>
@@ -1667,7 +1668,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Usar acceso directo"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversión de color"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Corrección de color"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reducir el brillo"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Como mantuviste presionadas las teclas de volumen, se activó <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Se presionaron las teclas de volumen. Se desactivó <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Mantén presionadas ambas teclas de volumen durante tres segundos para usar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Se cambió la solicitud SS por una videollamada"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Se cambió la solicitud SS por una solicitud USSD"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Se cambió a una nueva solicitud SS"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerta de suplantación de identidad (phishing)"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Perfil de trabajo"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Alerta enviada"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Expandir"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Para continuar, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&amp;gt necesita acceso a la cámara del dispositivo."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Activar"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privacidad del sensor"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 70cac4a..28ff5fb 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"No puede reconocer tu cara. Vuelve a intentarlo."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Se parece mucha a la anterior. Pon otra cara."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Gira la cabeza un poco menos."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Gira la cabeza un poco menos."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"No gires tanto la cabeza."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Retira cualquier objeto que te tape la cara."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Limpia la parte superior de la pantalla, incluida la barra de color negro"</string>
@@ -1667,7 +1668,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utilizar acceso directo"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversión de color"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Corrección de color"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reducir brillo"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Al mantener pulsadas las teclas de volumen, se ha activado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Se han mantenido pulsadas las teclas de volumen. Se ha desactivado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Para utilizar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, mantén pulsadas ambas teclas de volumen durante 3 segundos"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Se ha cambiado la solicitud de SS a una videollamada"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Se ha cambiado la solicitud de SS a una solicitud de USSD"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Se ha cambiado a una nueva solicitud de SS"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerta de phishing"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Perfil de trabajo"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Con sonido"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Mostrar"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Para continuar, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; necesita tener acceso a la cámara del dispositivo."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Activar"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privacidad del sensor"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 2a2db3a..cb2bcdc 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Nägu ei õnnestu enam tuvastada. Proovige uuesti."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Liiga sarnane, palun muutke oma asendit."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Pöörake oma pead veidi vähem."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Pöörake oma pead veidi vähem."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Pöörake oma pead veidi vähem."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Eemaldage kõik, mis varjab teie nägu."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Puhastage ekraani ülaosa, sh musta värvi riba"</string>
@@ -1667,7 +1668,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Kasuta otseteed"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Värvide ümberpööramine"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Värvide korrigeerimine"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Ereduse vähendamine"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Helitugevuse klahve hoiti all. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> lülitati sisse."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Helitugevuse klahve hoiti all. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> lülitati välja."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Teenuse <xliff:g id="SERVICE_NAME">%1$s</xliff:g> kasutamiseks hoidke kolm sekundit all mõlemat helitugevuse klahvi"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS-taotlus muudeti videokõneks"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS-taotlus muudeti USSD-taotluseks"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Muudeti uueks SS-taotluseks"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Andmepüügihoiatus"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Tööprofiil"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Teavitatud"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Laienda"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Jätkamiseks vajab rakendus &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; juurdepääsu teie seadme kaamerale."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Lülita sisse"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Anduri privaatsus"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 901d8661..f95c279 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -451,7 +451,7 @@
     <string name="permdesc_camera" msgid="5240801376168647151">"Aplikazioak abian den bitartean erabil dezake kamera argazkiak ateratzeko eta bideoak grabatzeko."</string>
     <string name="permlab_backgroundCamera" msgid="7549917926079731681">"Argazkiak atera eta bideoak grabatu atzeko planoan."</string>
     <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Aplikazioak edonoiz erabil dezake kamera argazkiak ateratzeko eta bideoak grabatzeko."</string>
-    <string name="permlab_systemCamera" msgid="3642917457796210580">"onartu aplikazio edo zerbitzu bati sistemako kamerak atzitzea argazkiak eta bideoak ateratzeko"</string>
+    <string name="permlab_systemCamera" msgid="3642917457796210580">"eman sistemako kamerak atzitzeko baimena aplikazio edo zerbitzu bati argazkiak ateratzeko eta bideoak grabatzeko"</string>
     <string name="permdesc_systemCamera" msgid="5938360914419175986">"Pribilegioa duen edo sistemakoa den aplikazio honek edonoiz erabil dezake kamera argazkiak ateratzeko eta bideoak grabatzeko. Halaber, android.permission.CAMERA baimena izan behar du aplikazioak."</string>
     <string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"eman jakinarazpenak jasotzeko baimena aplikazioari edo zerbitzuari kamerak ireki edo ixten direnean."</string>
     <string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Kamera ireki edo itxi dela (eta zer aplikaziorekin) dioten jakinarazpenak jaso ditzake aplikazio honek."</string>
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Ez dugu ezagutzen aurpegi hori. Saiatu berriro."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Jarrera berdintsuegia da. Alda ezazu."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Biratu burua pixka bat gutxiago."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Biratu burua pixka bat gutxiago."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Biratu burua pixka bat gutxiago."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Kendu aurpegia estaltzen dizuten gauzak."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Garbitu pantailaren goialdea, barra beltza barne"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Murriztu distira"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> erabiltzeko, eduki sakatuta bi bolumen-botoiak hiru segundoz"</string>
@@ -2219,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Aurrera egiteko, gailuaren kamera atzitzeko baimena behar du &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; aplikazioak."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Aktibatu"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sentsoreen pribatutasuna"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index ec195e5..714b5e4 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"دیگر چهره را تشخیص نمی‌دهد. دوباره امتحان کنید."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"بسیار شبیه قبلی است، لطفاً قیافه دیگری بگیرید."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"سرتان را کمی صاف بگیرید."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"سرتان را کمی صاف بگیرید."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"سرتان را کمی صاف بگیرید."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"هرچیزی را که حائل چهره‌تان است بردارید."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"بالای صفحه و همچنین نوار مشکی را تمیز کنید."</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"کاهش روشنایی"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"برای استفاده از <xliff:g id="SERVICE_NAME">%1$s</xliff:g>، هر دو کلید صدا را فشار دهید و سه ثانیه نگه دارید"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"‏درخواست SS به تماس تصویری تغییر کرد"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"‏درخواست SS به‌ درخواست USSD تغییر کرد"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"‏به‌ درخواست SS جدید تغییر کرد"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"هشدار رمزگیری"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"نمایه کاری"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"هشدار ارسال شد"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"بزرگ کردن"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"‏برای ادامه دادن، &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; باید به دوربین دستگاه دسترسی داشته باشد."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"روشن کردن"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"حریم‌خصوصی حسگر"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 6773dde..ef872e9 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Ei enää tunnista kasvoja. Yritä uudelleen."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Liian samanlainen, vaihda asentoa."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Käännä päätä vähän vähemmän."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Käännä päätä vähän vähemmän."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Käännä päätä vähän vähemmän."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Poista esteet kasvojesi edestä."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Puhdista näytön yläreuna, mukaan lukien musta palkki"</string>
@@ -1667,7 +1668,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Käytä pikanäppäintä"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Käänteiset värit"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Värinkorjaus"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Vähennä kirkkautta"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Äänenvoimakkuuspainikkeita painettiin pitkään. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> laitettiin päälle."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Äänenvoimakkuuspainikkeita painettiin pitkään. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> laitettiin pois päältä."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Voit käyttää palvelua <xliff:g id="SERVICE_NAME">%1$s</xliff:g> painamalla molempia äänenvoimakkuuspainikkeita kolmen sekunnin ajan"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS-pyyntö vaihdettu videopuheluksi"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS-pyyntö vaihdettu USSD-pyynnöksi"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Vaihdettu uudeksi SS-pyynnöksi"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Varoitus tietojenkalastelusta"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Työprofiili"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Hälytti"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Laajenna"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Jotta voit jatkaa, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; tarvitsee pääsyn laitteesi kameraan."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Laita päälle"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Anturin tietosuoja"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 9c4f92a..7cc3160 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Ce visage ne sera plus reconnu. Réessayez."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Trop similaire. Changez de pose."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Tournez un peu moins votre tête."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Tournez un peu moins votre tête."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Tournez un peu moins votre tête."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Retirez tout ce qui pourrait couvrir votre visage."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Nettoyez le haut de l\'écran, y compris la barre noire"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Réduire la luminosité"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Touches de volume maintenues enfoncées. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> activé."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Touches de volume maintenues enfoncées. Service <xliff:g id="SERVICE_NAME">%1$s</xliff:g> désactivé."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Maintenez enfoncées les deux touches de volume pendant trois secondes pour utiliser <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"La demande SS a été remplacée par une demande d\'appel vidéo"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"La demande SS a été remplacée par une demande USSD"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"La demande a été remplacée par une nouvelle demande SS"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerte d\'hameçonnage"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profil professionnel"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Alerté"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Développer"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Pour continuer, vous devez accorder l\'accès à l\'appareil photo de votre appareil à l\'application &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt;."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Activer"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Confidentialité des capteurs"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 78af86f..a3c0bad 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Impossible de reconnaître le visage. Réessayez."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Ressemble à un visage existant, changez de pose."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Tournez un peu moins la tête."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Tournez un peu moins la tête."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Tournez un peu moins la tête."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Retirez tout ce qui cache votre visage."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Nettoyez la partie supérieure de l\'écran, y compris la barre noire"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Réduire la luminosité"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Appuyez de manière prolongée sur les deux touches de volume pendant trois secondes pour utiliser <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Requête SS transformée en appel vidéo"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Requête SS transformée en requête USSD"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Remplacement par une nouvelle requête SS"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerte de hameçonnage"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profil professionnel"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Alerte envoyée"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Développer"</string>
@@ -2068,7 +2069,7 @@
     <string name="accessibility_system_action_back_label" msgid="4205361367345537608">"Retour"</string>
     <string name="accessibility_system_action_recents_label" msgid="4782875610281649728">"Applications récentes"</string>
     <string name="accessibility_system_action_notifications_label" msgid="6083767351772162010">"Notifications"</string>
-    <string name="accessibility_system_action_quick_settings_label" msgid="4583900123506773783">"Configuration rapide"</string>
+    <string name="accessibility_system_action_quick_settings_label" msgid="4583900123506773783">"Réglages rapides"</string>
     <string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Boîte de dialogue Marche/Arrêt"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Verrouiller l\'écran"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capture d\'écran"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Pour continuer, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; a besoin d\'accéder à l\'appareil photo de votre appareil."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Activer"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Confidentialité du capteur"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 949e486..72a799e 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Xa non se pode recoñecer a cara. Téntao de novo."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"É moi similar. Cambia a pose."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Xira a cabeza un pouco menos."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Xira a cabeza un pouco menos."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Xira a cabeza un pouco menos."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Quita todo o que oculte a túa cara."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Limpa a parte superior da pantalla, incluída a barra de cor negra"</string>
@@ -1667,7 +1668,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utilizar atallo"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversión de cor"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Corrección de cor"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reducir brillo"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas de volume premidas. Activouse o servizo <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume premidas. Desactivouse <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Mantén premidas as teclas do volume durante tres segudos para usar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"A solicitude SS transformouse nunha videochamada"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"A solicitude SS transformouse nunha solicitude USSD"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Transformouse nunha nova solicitude SS"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerta de phishing"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Perfil de traballo"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Con son"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Despregar"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Para continuar, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; precisa acceder á cámara do dispositivo."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Activar"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privacidade do sensor"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 29ce76b..7a2527f 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"ચહેરો ઓળખી શકાતો નથી. ફરી પ્રયાસ કરો."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"ઘણી સમાનતા ધરાવે છે, કૃપા કરીને તમારો પોઝ બદલો."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"તમારું માથું થોડું ફેરવો."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"તમારું માથું થોડું ફેરવો."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"તમારું માથું થોડું ઓછું ફેરવો."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"તમારા ચહેરાને છુપાવતી કંઈપણ વસ્તુ દૂર કરો."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"કાળી પટ્ટી સહિત, તમારી સ્ક્રીનની ટોચ સાફ કરો"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"બ્રાઇટનેસ ઘટાડો"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>નો ઉપયોગ કરવા માટે બન્ને વૉલ્યૂમ કીને ત્રણ સેકન્ડ સુધી દબાવી રાખો"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS વિનંતીને વીડિઓ કૉલમાં બદલવામાં આવી છે"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS વિનંતીને USSD વિનંતીમાં બદલવામાં આવી છે"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"નવી SS વિનંતીમાં બદલવામાં આવી છે"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ફિશિંગ અલર્ટ"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"ઑફિસની પ્રોફાઇલ"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"અલર્ટ કરેલ"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"વિસ્તૃત કરો"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"ચાલુ રાખવા માટે, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt;ને તમારા ડિવાઇસના કૅમેરાના ઍક્સેસની જરૂર છે."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ચાલુ કરો"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"સેન્સર પ્રાઇવસી સંબંધિત નોટિફિકેશન"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 15bb461..f108aa7 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"अब चेहरे की पहचान नहीं कर पा रहा. फिर से कोशिश करें."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"चेहरा काफ़ी मिलता-जुलता है, कृपया अपना पोज़ बदलें."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"अपना सिर थोड़ा कम घुमाएं."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"अपना सिर थोड़ा कम घुमाएं."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"अपना सिर थोड़ा कम घुमाएं."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"आपके चेहरे को छिपाने वाली सभी चीज़ों को हटाएं."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"अपनी स्क्रीन के सबसे ऊपरी हिस्से को साफ़ करें, जिसमें काले रंग वाला बार भी शामिल है"</string>
@@ -685,7 +686,7 @@
     <string name="permdesc_access_notification_policy" msgid="8538374112403845013">"ऐप को परेशान न करें कॉन्फ़िगरेशन पढ़ने और लिखने देती है."</string>
     <string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"देखने की अनुमतियां चालू करें"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"इस्तेमाल करने वाले को किसी ऐप्लिकेशन के लिए अनुमतियों का इस्तेमाल शुरू करने देता है. सामान्य ऐप्लिकेशन के लिए इसकी ज़रूरत कभी नहीं पड़ती."</string>
-    <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"सेंसर डेटा को नमूने लेने की तेज़ दर पर ऐक्सेस करें"</string>
+    <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"सेंसर डेटा को, नमूने लेने की तेज़ दर पर ऐक्सेस करें"</string>
     <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"यह अनुमति मिलने पर ऐप्लिकेशन, 200 हर्ट्ज़ से ज़्यादा की दर पर सेंसर डेटा का नमूना ले पाएगा"</string>
     <string name="policylab_limitPassword" msgid="4851829918814422199">"पासवर्ड नियम सेट करना"</string>
     <string name="policydesc_limitPassword" msgid="4105491021115793793">"स्‍क्रीन लॉक पासवर्ड और पिन की लंबाई और उनमें स्वीकृत वर्णों को नियंत्रित करना."</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"स्क्रीन की चमक कम करें"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> इस्तेमाल करने के लिए आवाज़ वाले दोनों बटन तीन सेकंड तक दबाकर रखें"</string>
@@ -2219,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"जारी रखने के लिए, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; को आपके डिवाइस का कैमरा ऐक्सेस करने की ज़रूरत है."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"चालू करें"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"सेंसर से जुड़ी निजता के बारे में सूचना"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 6e7c330..91073d4 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -609,7 +609,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Lice nije prepoznato. Pokušajte ponovo."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Previše slično, promijenite pozu."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Nagnite glavu malo manje."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Nagnite glavu malo manje."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Nagnite glavu malo manje."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Uklonite sve što vam zakriva lice."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Očistite vrh zaslona, uključujući crnu traku"</string>
@@ -1689,7 +1690,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Upotrijebi prečac"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Inverzija boja"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Korekcija boje"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Smanjenje svjetline"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Držali ste tipke za glasnoću. Uključila se usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Držali ste tipke za glasnoću. Isključila se usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Pritisnite i zadržite tipke za glasnoću na tri sekunde da biste koristili uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2253,4 +2255,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Da bi nastavila s radom, aplikacija &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; treba pristupiti fotoaparatu vašeg uređaja."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Uključi"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privatnost senzora"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index d966249..32f33df 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Már nem lehet felismerni az arcát. Próbálja újra."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Túlságosan hasonló, változtasson a pózon."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Kicsit kevésbé fordítsa el a fejét."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Kicsit kevésbé fordítsa el a fejét."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Kicsit kevésbé fordítsa el a fejét."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Távolítson el mindent, ami takarja az arcát."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Tisztítsa meg a képernyő tetejét, a fekete sávot is beleértve."</string>
@@ -1667,7 +1668,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Billentyűparancs használata"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Színek invertálása"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Színkorrekció"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Fényerő csökkentése"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Nyomva tartotta a hangerőgombokat. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> bekapcsolva."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Nyomva tartotta a hangerőgombokat. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> kikapcsolva."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"A(z) <xliff:g id="SERVICE_NAME">%1$s</xliff:g> használatához tartsa lenyomva három másodpercig a két hangerőgombot"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Az SS-kérés módosítva videohívásra"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Az SS-kérés módosítva USSD-kérésre"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Új SS-kérésre módosítva"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Adathalászati figyelmeztetés"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Munkaprofil"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Értesítve"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Kibontás"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"A folytatáshoz a(z) &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; alkalmazásnak hozzáférésre van szüksége az eszköze kamerájához."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Bekapcsolás"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Érzékelőkkel kapcsolatos adatvédelem"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 6110be3..cd1bbb1 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Չհաջողվեց ճանաչել դեմքը։ Նորից փորձեք:"</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Շատ նման է նախորդին։ Փոխեք ձեր դիրքը։"</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Գլուխն ուղիղ պահեք։"</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Գլուխն ուղիղ պահեք։"</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Գլուխն ուղիղ պահեք։"</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Հեռացրեք այն ամենը, ինչը թաքցնում է ձեր երեսը:"</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Մաքրեք էկրանի վերևի մասը, ներառյալ սև գոտին"</string>
@@ -686,7 +687,7 @@
     <string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"թույլտվությունների մասին տվյալների հասանելիություն"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Հավելվածին հասանելի կդառնան թույլտվությունների մասին տվյալները։ Այս թույլտվությունն անհրաժեշտ չէ սովորական հավելվածներին։"</string>
     <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"օգտագործել սենսորների տվյալները բարձր հաճախականության վրա"</string>
-    <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Թույլ է տալիս հավելվածին փորձել սենսորների տվյալները 200 Հց-ից ավել հաճախականության վրա"</string>
+    <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Թույլ է տալիս հավելվածին փորձել սենսորների տվյալները 200 Հց-ից բարձր հաճախականության վրա"</string>
     <string name="policylab_limitPassword" msgid="4851829918814422199">"Սահմանել գաղտնաբառի կանոնները"</string>
     <string name="policydesc_limitPassword" msgid="4105491021115793793">"Կառավարել էկրանի ապակողպման գաղտնաբառերի և PIN կոդերի թույլատրելի երկարությունն ու գրանշանները:"</string>
     <string name="policylab_watchLogin" msgid="7599669460083719504">"Վերահսկել էկրանի ապակողպման փորձերը"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Նվազեցնել պայծառությունը"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"«<xliff:g id="SERVICE_NAME">%1$s</xliff:g>» ծառայությունն օգտագործելու համար սեղմեք և 3 վայրկյան պահեք ձայնի ուժգնության երկու կոճակները"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS հարցումը փոխվել է տեսազանգի"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS հարցումը փոխվել է USSD հարցման"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Փոխվել է նոր SS հարցման"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Ֆիշինգի մասին զգուշացում"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Աշխատանքային պրոֆիլ"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Ուղարկվել է զգուշացում"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Ընդարձակել"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Շարունակելու համար &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; հավելվածին անհրաժեշտ է ձեր սարքի տեսախցիկի օգտագործման թույլտվություն։"</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Միացնել"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Տվիչների գաղտնիություն"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 3335f59..f7fe384 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Tidak lagi dapat mengenali wajah. Coba lagi."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Terlalu mirip, ubah pose Anda."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Putar sedikit kepala Anda."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Putar sedikit kepala Anda."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Putar sedikit kepala Anda."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Singkirkan apa saja yang menutupi wajah Anda."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Bersihkan bagian atas layar, termasuk kotak hitam"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Kurangi Kecerahan"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Tekan dan tahan kedua tombol volume selama tiga detik untuk menggunakan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Permintaan SS diubah ke panggilan video"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Permintaan SS diubah ke permintaan USSD"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Diubah ke permintaan SS baru"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Peringatan phishing"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profil kerja"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Diingatkan"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Luaskan"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Untuk melanjutkan, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; memerlukan akses ke kamera perangkat."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Aktifkan"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privasi Sensor"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 86a4638..5824c3a6 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Andlit þekkist ekki lengur. Reyndu aftur."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Of svipað. Stilltu þér öðruvísi upp."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Snúðu höfðinu aðeins minna."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Hallaðu höfðinu aðeins minna."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Snúðu höfðinu aðeins minna."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Fjarlægðu það sem kann að hylja andlitið."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Hreinsaðu efsta hluta skjásins þíns, þ.m.t. svörtu stikuna"</string>
@@ -1667,7 +1668,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Nota flýtileið"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Umsnúningur lita"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Litaleiðrétting"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Draga úr birtu"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Hljóðstyrkstökkum haldið inni. Kveikt á <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Hljóðstyrkstökkum haldið inni. Slökkt á <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Haltu báðum hljóðstyrkstökkunum inni í þrjár sekúndur til að nota <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS-beiðni breytt í myndsímtal"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS-beiðni breytt í USSD-beiðni"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Breytt í nýja SS-beiðni"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Viðvörun um vefveiðar"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Vinnusnið"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Tilkynnt"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Stækka"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Til að halda áfram þarf &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; aðgang að myndavél tækisins."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Kveikja"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Persónuvernd skynjara"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index fa6b461..d435a25 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Non è più possibile riconoscere il volto. Riprova."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Troppo simile; cambia posa."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Gira un po\' meno la testa."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Gira un po\' meno la testa."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Gira un po\' meno la testa."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Rimuovi tutto ciò che ti nasconde il viso."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Pulisci la parte superiore dello schermo, inclusa la barra nera"</string>
@@ -1667,7 +1668,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Usa scorciatoia"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversione dei colori"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Correzione del colore"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Riduci la luminosità"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tieni premuti i tasti del volume. Servizio <xliff:g id="SERVICE_NAME">%1$s</xliff:g> attivato."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tieni premuti i tasti del volume. Servizio <xliff:g id="SERVICE_NAME">%1$s</xliff:g> disattivato."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Tieni premuti entrambi i tasti del volume per tre secondi per utilizzare <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Richiesta SS modificata in videochiamata"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Richiesta SS modificata in richiesta USSD"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Modificata in nuova richiesta SS"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Allerta phishing"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profilo di lavoro"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Avviso inviato"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Espandi"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Per continuare, l\'app &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; deve accedere alla videocamera del dispositivo."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Attiva"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privacy relativa ai sensori"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index d9b889e..ee771df 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -612,7 +612,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"כבר לא ניתן לזהות פנים. יש לנסות שוב."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"דומה מדי, יש לשנות תנוחה."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"עליך ליישר קצת את הראש."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"עליך ליישר קצת את הראש."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"עליך ליישר קצת את הראש."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"יש להסיר כל דבר שמסתיר את הפנים."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"עליך לנקות את החלק העליון של המסך, כולל הסרגל השחור"</string>
@@ -1711,7 +1712,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"הפחתה של עוצמת הבהירות"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"יש ללחוץ לחיצה ארוכה על שני לחצני עוצמת הקול למשך שלוש שניות כדי להשתמש בשירות <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1933,8 +1935,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"‏בקשת SS שונתה לשיחת וידאו"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"‏בקשת SS שונתה לבקשת USSD"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"‏היה שינוי לבקשת SS חדשה"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"התראה על פישינג"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"פרופיל עבודה"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"נשלחה התראה"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"הרחב"</string>
@@ -2288,4 +2289,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"‏כדי להמשיך, האפליקציה &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; צריכה גישה למצלמה של המכשיר שלך."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"הפעלה"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"פרטיות חיישנים"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 68213def..b03f94c 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -538,10 +538,10 @@
     <string name="permdesc_requestPasswordComplexity" msgid="1130556896836258567">"このアプリに画面ロックの複雑さレベル(高、中、低、なし)を認識することを許可します。複雑さレベルは、画面ロックの文字数の範囲やタイプを示すものです。アプリから一定レベルまで画面ロックを更新するよう推奨されることもありますが、ユーザーは無視したり別の操作を行ったりできます。画面ロックは平文で保存されないため、アプリが正確なパスワードを知ることはありません。"</string>
     <string name="permlab_useBiometric" msgid="6314741124749633786">"生体認証ハードウェアの使用"</string>
     <string name="permdesc_useBiometric" msgid="7502858732677143410">"生体認証ハードウェアを認証に使用することをアプリに許可します"</string>
-    <string name="permlab_manageFingerprint" msgid="7432667156322821178">"指紋ハードウェアの管理"</string>
+    <string name="permlab_manageFingerprint" msgid="7432667156322821178">"指紋認証ハードウェアの管理"</string>
     <string name="permdesc_manageFingerprint" msgid="2025616816437339865">"使用する指紋テンプレートの追加や削除を行う方法の呼び出しをアプリに許可します。"</string>
-    <string name="permlab_useFingerprint" msgid="1001421069766751922">"指紋ハードウェアの使用"</string>
-    <string name="permdesc_useFingerprint" msgid="412463055059323742">"指紋ハードウェアを認証に使用することをアプリに許可します"</string>
+    <string name="permlab_useFingerprint" msgid="1001421069766751922">"指紋認証ハードウェアの使用"</string>
+    <string name="permdesc_useFingerprint" msgid="412463055059323742">"指紋認証ハードウェアを認証に使用することをアプリに許可します"</string>
     <string name="permlab_audioWrite" msgid="8501705294265669405">"音楽コレクションの変更"</string>
     <string name="permdesc_audioWrite" msgid="8057399517013412431">"音楽コレクションの変更をアプリに許可します。"</string>
     <string name="permlab_videoWrite" msgid="5940738769586451318">"動画コレクションの変更"</string>
@@ -567,7 +567,7 @@
     <string name="fingerprint_authenticated" msgid="2024862866860283100">"指紋認証を完了しました"</string>
     <string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"顔を認証しました"</string>
     <string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"顔を認証しました。[確認] を押してください"</string>
-    <string name="fingerprint_error_hw_not_available" msgid="4571700896929561202">"指紋ハードウェアは使用できません。"</string>
+    <string name="fingerprint_error_hw_not_available" msgid="4571700896929561202">"指紋認証ハードウェアは使用できません。"</string>
     <string name="fingerprint_error_no_space" msgid="6126456006769817485">"指紋を保存できません。既存の指紋を削除してください。"</string>
     <string name="fingerprint_error_timeout" msgid="2946635815726054226">"指紋の読み取りがタイムアウトになりました。もう一度お試しください。"</string>
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"指紋の操作をキャンセルしました。"</string>
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"顔を認識できなくなりました。もう一度お試しください。"</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"似すぎています。ポーズを変えてください。"</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"顔の向きを少し戻してください。"</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"顔の向きを少し戻してください。"</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"顔の向きを少し戻してください。"</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"顔を隠しているものをすべて外してください"</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"黒いバーを含め、画面の上部をきれいにしてください"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"明るさを下げる"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"音量ボタンを長押ししました。<xliff:g id="SERVICE_NAME">%1$s</xliff:g> が ON になりました。"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"音量ボタンを長押ししました。<xliff:g id="SERVICE_NAME">%1$s</xliff:g> が OFF になりました。"</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> を使用するには、音量大と音量小の両方のボタンを 3 秒間長押ししてください"</string>
@@ -2219,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"続行するには、&lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; にデバイスのカメラへのアクセスを許可する必要があります。"</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ON にする"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"センサー プライバシー"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 3c76454..c25bd57 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"სახის ამოცნობა ვეღარ ხერხდება. ცადეთ ხელახლა."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"მეტისმეტად მსგავსია. გთხოვთ, შეცვალოთ პოზა."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"თავი ცოტა ნაკლებად მიაბრუნეთ."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"თავი ცოტა ნაკლებად მიაბრუნეთ."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"თავი ცოტა ნაკლებად მიაბრუნეთ."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"მოაშორეთ ყველაფერი, რაც სახეს გიფარავთ."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"გაწმინდეთ ეკრანის ზედა ნაწილი, შავი ზოლის ჩათვლით."</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"სიკაშკაშის შემცირება"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> რომ გამოიყენოთ, დააჭირეთ ხმის ორივე ღილაკზე 3 წამის განმავლობაში"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS მოთხოვნა შეიცვალა ვიდეოზარის მოთხოვნით"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS მოთხოვნა შეიცვალა USSD მოთხოვნით"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"შეიცვალა ახალი SS მოთხოვნით"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"გაფრთხილება ფიშინგის შესახებ"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"სამსახურის პროფილი"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"გაფრთხილებით"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"გაშლა"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"გასაგრძელებლად &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt;-ს თქვენი მოწყობილობის კამერაზე წვდომა სჭირდება."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ჩართვა"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"სენსორის კონფიდენციალურობა"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 38f9475..68edfea 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Енді бет анықтау мүмкін емес. Әрекетті қайталаңыз."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Алдыңғысына тым ұқсас, басқаша қалыпта түсіңіз."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Басыңызды түзурек ұстаңыз."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Басыңызды түзурек ұстаңыз."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Басыңызды кішкене бұрыңыз."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Бетіңізді жауып тұрған нәрсені алып тастаңыз."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Экранның жоғарғы жағын, сонымен қатар қара жолақты өшіріңіз."</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Жарықтығын азайту"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> қызметін пайдалану үшін дыбыс деңгейін реттейтін екі түймені де 3 секунд басып тұрыңыз"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS сұрауы бейне қоңырауға өзгертілді"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS сұрауы USSD сұрауына өзгертілді"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Жаңа SS сұрауына өзгертілді"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Фишинг ескертуі"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Жұмыс профилі"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Ескертілді"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Жаю"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Жалғастыру үшін &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; қолданбасы құрылғыңыздың камерасына рұқсат алу керек."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Қосу"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Датчикке қатысты құпиялылық"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 5bde733..b3516d5 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"មិន​អាច​សម្គាល់មុខ​បាន​ទៀតទេ។ សូមព្យាយាមម្ដងទៀត។"</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"ស្រដៀងគ្នា​ពេក សូមផ្លាស់ប្ដូរ​កាយវិការ​របស់អ្នក។"</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ងាកក្បាល​របស់អ្នកតិចជាងមុន​បន្តិច។"</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"ងាកក្បាល​របស់អ្នកតិចជាងមុន​បន្តិច។"</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ងាកក្បាល​របស់អ្នក​បន្តិចទៀត។"</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"យកអ្វី​ដែលបាំង​មុខ​របស់អ្នកចេញ។"</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"សម្អាតផ្នែកខាង​លើនៃ​អេក្រង់​របស់​អ្នក រួមទាំង​របារខ្មៅ"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"បន្ថយពន្លឺ"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"ចុចគ្រាប់ចុច​កម្រិត​សំឡេងទាំងពីរ​ឱ្យជាប់រយៈពេលបីវិនាទី ដើម្បីប្រើ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"ដើម្បីបន្ត &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; ត្រូវការសិទ្ធិ​ចូលប្រើ​កាមេរ៉ា​របស់ឧបករណ៍អ្នក។"</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"បើក"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"ឯកជនភាព​ឧបករណ៍​ចាប់សញ្ញា"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index cf0f644..22bdd77 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"ಮುಖ ಗುರುತಿಸಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"ತುಂಬಾ ಸಮಾನ, ನಿಮ್ಮ ಪೋಸ್ ಬದಲಾಯಿಸಿ."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ನಿಮ್ಮ ತಲೆಯನ್ನು ಹೆಚ್ಚು ತಿರುಗಿಸಬೇಡಿ."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"ನಿಮ್ಮ ತಲೆಯನ್ನು ಹೆಚ್ಚು ತಿರುಗಿಸಬೇಡಿ."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ನಿಮ್ಮ ತಲೆಯನ್ನು ಸ್ವಲ್ಪ ಕಡಿಮೆ ತಿರುಗಿಸಿ."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"ನಿಮ್ಮ ಮುಖವನ್ನು ಮರೆಮಾಡುವ ಯಾವುದನ್ನಾದರೂ ತೆಗೆದುಹಾಕಿ."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ಬ್ಲ್ಯಾಕ್ ಬಾರ್ ಸೇರಿದಂತೆ ನಿಮ್ಮ ಸ್ಕ್ರೀನ್‌ನ ಮೇಲ್ಭಾಗವನ್ನು ತೆರವುಗೊಳಿಸಿ"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ಪ್ರಖರತೆಯನ್ನು ಕಡಿಮೆ ಮಾಡಿ"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಬಳಸಲು ಎರಡೂ ಧ್ವನಿ ಕೀಗಳನ್ನು ಮೂರು ಸೆಕೆಂಡ್‌ಗಳ ಕಾಲ ಒತ್ತಿ ಹಿಡಿದುಕೊಳ್ಳಿ"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS ವಿನಂತಿಯನ್ನು ವೀಡಿಯೊ ಕರೆಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS ವಿನಂತಿಯನ್ನು USSD ವಿನಂತಿಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"ಹೊಸ SS ವಿನಂತಿಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ಫಿಶಿಂಗ್ ಕುರಿತು ಎಚ್ಚರಿಕೆ‌"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"ಎಚ್ಚರಿಕೆ ನೀಡಲಾಗಿದೆ"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"ವಿಸ್ತೃತಗೊಳಿಸಿ"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"ಮುಂದುವರಿಯಲು, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; ಗೆ ನಿಮ್ಮ ಸಾಧನದ ಕ್ಯಾಮರಾದ ಪ್ರವೇಶದ ಅಗತ್ಯವಿದೆ."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ಆನ್ ಮಾಡಿ"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"ಸೆನ್ಸರ್ ಗೌಪ್ಯತೆ"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 8fde34c..52f0a7c 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"더 이상 얼굴을 인식할 수 없습니다. 다시 시도하세요."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"너무 비슷합니다. 다른 포즈를 취해 보세요."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"고개를 조금 덜 돌려 보세요."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"고개를 조금 덜 돌려 보세요."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"고개를 조금 덜 돌려 보세요."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"얼굴이 가려지지 않도록 해 주세요."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"검은색 바를 포함한 화면 상단을 청소하세요."</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"밝기 낮추기"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> 서비스를 사용하려면 두 볼륨 키를 3초 동안 길게 누르세요"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS 요청이 화상 통화로 변경됨"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS 요청이 USSD 요청으로 변경됨"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"새 SS 요청으로 변경됨"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"피싱 알림"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"직장 프로필"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"알림 전송됨"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"펼치기"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"계속하려면 &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt;에서 기기 카메라에 액세스해야 합니다."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"사용"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"센서 개인정보 보호"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index aa5d01c..4d8888e 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Жүз таанылган жок. Кайталап көрүңүз."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Мурункуга окшош болуп калды, башкача туруңуз."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Башыңызды бир аз гана эңкейтиңиз."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Башыңызды бир аз гана эңкейтиңиз."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Башыңызды бир аз гана эңкейтиңиз."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Жүзүңүздү жашырып турган нерселерди алып салыңыз."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Экраныңыздын жогору жагын, анын ичинде тилкени да тазалаңыз"</string>
@@ -1206,7 +1207,7 @@
     <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"Жаңыртууну издөө"</string>
     <string name="smv_application" msgid="3775183542777792638">"<xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосу (<xliff:g id="PROCESS">%2$s</xliff:g> процесси) өз алдынча иштеткен StrictMode саясатын бузду."</string>
     <string name="smv_process" msgid="1398801497130695446">"<xliff:g id="PROCESS">%1$s</xliff:g> процесси өзүнүн мажбурланган StrictMode саясатын бузуп койду."</string>
-    <string name="android_upgrading_title" product="default" msgid="7279077384220829683">"Телефон жаңыртылууда…"</string>
+    <string name="android_upgrading_title" product="default" msgid="7279077384220829683">"Телефон жаңырууда…"</string>
     <string name="android_upgrading_title" product="tablet" msgid="4268417249079938805">"Планшет жаңыртылууда…"</string>
     <string name="android_upgrading_title" product="device" msgid="6774767702998149762">"Түзмөк жаңыртылууда…"</string>
     <string name="android_start_title" product="default" msgid="4036708252778757652">"Телефон күйгүзүлүүдө…"</string>
@@ -1216,7 +1217,7 @@
     <string name="android_upgrading_fstrim" msgid="3259087575528515329">"Сактагыч ыңгайлаштырылууда."</string>
     <string name="android_upgrading_notification_title" product="default" msgid="3509927005342279257">"Тутумду жаңыртуу аяктоодо…"</string>
     <string name="app_upgrading_toast" msgid="1016267296049455585">"<xliff:g id="APPLICATION">%1$s</xliff:g> жаңыртылууда..."</string>
-    <string name="android_upgrading_apk" msgid="1339564803894466737">"<xliff:g id="NUMBER_1">%2$d</xliff:g> ичинен <xliff:g id="NUMBER_0">%1$d</xliff:g> колдонмо ыңгайлаштырылууда."</string>
+    <string name="android_upgrading_apk" msgid="1339564803894466737">"<xliff:g id="NUMBER_1">%2$d</xliff:g> ичинен <xliff:g id="NUMBER_0">%1$d</xliff:g> колдонмо оптималдаштырылууда."</string>
     <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>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Экрандын жарыктыгын төмөндөтүү"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> кызматын колдонуу үчүн үнүн чоңойтуп/кичирейтүү баскычтарын үч секунд коё бербей басып туруңуз"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS сурамы видео чалууга өзгөртүлдү"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS сурамы USSD сурамына өзгөртүлдү"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Жаңы SS сурамына өзгөртүлдү"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Фишинг жөнүндө эскертүү"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Жумуш профили"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Эскертилди"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Жайып көрсөтүү"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Улантуу үчүн &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; колдонмосуна түзмөгүңүздүн камерасын пайдаланууга уруксат беришиңиз керек."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Күйгүзүү"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Сенсордун купуялыгы"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 806a5e2..87c2ceb 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"ບໍ່ສາມາດຈຳແນກໃບໜ້າໄດ້ອີກຕໍ່ໄປ. ກະລຸນາລອງໃໝ່."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"ຄ້າຍກັນເກີນໄປ, ກະລຸນາປ່ຽນທ່າຂອງທ່ານ."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ອຽງຫົວຂອງທ່ານໜ້ອຍໜຶ່ງ."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"ອຽງຫົວຂອງທ່ານໜ້ອຍໜຶ່ງ."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ອຽງຫົວຂອງທ່ານໜ້ອຍໜຶ່ງ."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"ນຳສິ່ງທີ່ກີດຂວາງໃບໜ້າທ່ານອອກ."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ທຳຄວາມສະອາດສ່ວນເທິງສຸດຂອງໜ້າຈໍທ່ານ, ຮວມທັງແຖບດຳນຳ"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ຫຼຸດຄວາມສະຫວ່າງ"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"ກົດປຸ່ມສຽງທັງສອງພ້ອມກັນຄ້າງໄວ້ສາມວິນາທີເພື່ອໃຊ້ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"ເພື່ອດຳເນີນການຕໍ່, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; ຕ້ອງການສິດເຂົ້າເຖິງກ້ອງຖ່າຍຮູບຂອງອຸປະກອນທ່ານ."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ເປີດໃຊ້"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"ຄວາມເປັນສ່ວນຕົວເຊັນເຊີ"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 8f64bdd..2c3742b 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -612,7 +612,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Nebegalima atpažinti veido. Bandykite dar kartą."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Per daug panašu, pakeiskite veido išraišką."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Nesukite tiek galvos."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Nesukite tiek galvos."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Nesukite tiek galvos."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Patraukite viską, kas užstoja jūsų veidą."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Išvalykite ekrano viršų, įskaitant juodą juostą"</string>
@@ -1711,7 +1712,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Naudoti spartųjį klavišą"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Spalvų inversija"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Spalvų taisymas"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Šviesumo mažinimas"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Laikomi garsumo klavišai. „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“ įjungta."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Laikomi garsumo klavišai. „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“ išjungta."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Jei norite naudoti „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“, paspauskite abu garsumo klavišus ir palaikykite tris sekundes"</string>
@@ -1933,8 +1935,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS užklausa pakeista į vaizdo skambutį"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS užklausa pakeista į USSD užklausą"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Pakeista į naują SS užklausą"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Įspėjimas apie sukčiavimą"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Darbo profilis"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Įspėjimas išsiųstas"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Išskleisti"</string>
@@ -2288,4 +2289,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Kad būtų galima tęsti, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; reikalinga prieiga prie įrenginio fotoaparato."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Įjungti"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Jutiklių privatumas"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 346ade4..8d6ce86 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -609,7 +609,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Seju vairs nevar atpazīt. Mēģiniet vēlreiz."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Pārāk līdzīgi. Lūdzu, mainiet pozu."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Pagrieziet galvu nedaudz mazāk."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Pagrieziet galvu nedaudz mazāk."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Pagrieziet galvu nedaudz mazāk."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Noņemiet visu, kas aizsedz jūsu seju."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Notīriet ekrāna augšdaļu, tostarp melno joslu."</string>
@@ -1689,7 +1690,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Izmantot saīsni"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Krāsu inversija"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Krāsu korekcija"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Spilgtuma samazināšana"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Turējāt nospiestas skaļuma pogas. Pakalpojums <xliff:g id="SERVICE_NAME">%1$s</xliff:g> tika ieslēgts."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Turējāt nospiestas skaļuma pogas. Pakalpojums <xliff:g id="SERVICE_NAME">%1$s</xliff:g> tika izslēgts."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Lai izmantotu pakalpojumu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, nospiediet abus skaļuma taustiņus un turiet tos trīs sekundes."</string>
@@ -1902,8 +1904,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS pieprasījums mainīts uz videozvanu"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS pieprasījums mainīts uz USSD pieprasījumu"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Mainīts uz jaunu SS pieprasījumu"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Brīdinājums par pikšķerēšanu"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Darba profils"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Brīdināts"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Izvērst"</string>
@@ -2254,4 +2255,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Lai turpinātu, lietotnei &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; nepieciešama piekļuve jūsu ierīces kamerai."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Ieslēgt"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensoru konfidencialitāte"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 8d176ad..af3ce00 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Ликот не се препознава. Обидете се повторно."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Премногу слично, сменете ја позата."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Не вртете ја главата толку многу."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Не вртете ја главата толку многу."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Не вртете ја главата толку многу."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Отстранете ги работите што ви го покриваат лицето."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Исчистете го врвот на екранот, вклучувајќи ја црната лента"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Намалете ја осветленоста"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Притиснете ги и задржете ги двете копчиња за јачина на звукот во траење од три секунди за да користите <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Барањето SS е изменето во видео повик"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Барањето SS е изменето во барање USSD"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Променето на ново барање SS"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Предупредување за фишинг"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Работен профил"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Предупредено"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Прошири"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"За да продолжи, на &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; ѝ е потребен пристап до камерата на уредот."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Вклучи"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Приватност на сензорот"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index fd61768..aaab7b5 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"ഇനി മുഖം തിരിച്ചറിയാനാവില്ല. വീണ്ടും ശ്രമിക്കൂ."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"വളരെയധികം സമാനത, നിങ്ങളുടെ പോസ് മാറ്റുക."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"നിങ്ങളുടെ തല ഇത്ര തിരിക്കേണ്ട."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"നിങ്ങളുടെ തല ഇത്ര തിരിക്കേണ്ട."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"നിങ്ങളുടെ തല ഇത്ര തിരിക്കേണ്ട."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"നിങ്ങളുടെ മുഖം മറയ്‌ക്കുന്നത് എല്ലാം നീക്കം ചെയ്യൂ."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"കറുപ്പ് ബാർ ഉൾപ്പെടെ നിങ്ങളുടെ സ്ക്രീനിന്റെ മുകൾഭാഗം വൃത്തിയാക്കുക"</string>
@@ -685,10 +686,8 @@
     <string name="permdesc_access_notification_policy" msgid="8538374112403845013">"\'ശല്യപ്പെടുത്തരുത്\' കോൺഫിഗറേഷൻ വായിക്കുന്നതിനും എഴുതുന്നതിനും ആപ്പിനെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"അനുമതി ഉപയോഗം കാണാൻ ആരംഭിക്കുക"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"ഒരു ആപ്പിനുള്ള അനുമതി ഉപയോഗം ആരംഭിക്കാൻ ഹോൾഡറിനെ അനുവദിക്കുന്നു. സാധാരണ ആപ്പുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
-    <!-- no translation found for permlab_highSamplingRateSensors (3941068435726317070) -->
-    <skip />
-    <!-- no translation found for permdesc_highSamplingRateSensors (8430061978931155995) -->
-    <skip />
+    <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"ഉയർന്ന സാം‍പ്ലിംഗ് റേറ്റിൽ സെൻസർ ഡാറ്റ ആക്സസ് ചെയ്യുക"</string>
+    <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"200 Hz-നേക്കാൾ ഉയർന്ന റേറ്റിൽ സെൻസർ ഡാറ്റ സാമ്പിൾ ചെയ്യാൻ ആപ്പിനെ അനുവദിക്കുന്നു"</string>
     <string name="policylab_limitPassword" msgid="4851829918814422199">"പാസ്‌വേഡ് നിയമങ്ങൾ സജ്ജീകരിക്കുക"</string>
     <string name="policydesc_limitPassword" msgid="4105491021115793793">"സ്‌ക്രീൻ ലോക്ക് പാസ്‌വേഡുകളിലും PIN-കളിലും അനുവദിച്ചിരിക്കുന്ന ദൈർഘ്യവും പ്രതീകങ്ങളും നിയന്ത്രിക്കുക."</string>
     <string name="policylab_watchLogin" msgid="7599669460083719504">"സ്‌ക്രീൻ അൺലോക്ക് ശ്രമങ്ങൾ നിരീക്ഷിക്കുക"</string>
@@ -1669,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"തെളിച്ചം കുറയ്ക്കുക"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഉപയോഗിക്കാൻ, രണ്ട് വോളിയം കീകളും മൂന്ന് സെക്കൻഡ് അമർത്തിപ്പിടിക്കുക"</string>
@@ -1873,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS അഭ്യർത്ഥന, വീഡിയോ കോളിലേക്ക് മാറ്റി"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS അഭ്യർത്ഥന, USSD അഭ്യർത്ഥനയിലേക്ക് മാറ്റി"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"പുതിയ SS അഭ്യർത്ഥനയിലേക്ക് മാറ്റി"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ഫിഷിംഗ് മുന്നറിയിപ്പ്"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"ഔദ്യോഗിക പ്രൊഫൈൽ"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"മുന്നറിയിപ്പ് നൽകി"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"വികസിപ്പിക്കുക"</string>
@@ -2222,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"തുടരാൻ, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; ആപ്പിന് നിങ്ങളുടെ ഉപകരണത്തിന്റെ ക്യാമറയിലേക്ക് ആക്‌സസ് നൽകേണ്ടതുണ്ട്."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ഓണാക്കുക"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"സെൻസർ സ്വകാര്യത"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index d5937d3..c699285 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Царайг таних боломжгүй боллоо. Дахин оролдоно уу."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Хэт адилхан байгаа тул байрлалаа өөрчилнө үү."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Толгойгоо арай багаар эргүүлнэ үү."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Толгойгоо арай багаар эргүүлнэ үү."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Толгойгоо арай багаар эргүүлнэ үү."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Таны нүүрийг далдалж буй аливаа зүйлийг хасна уу."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Хар хэсэг зэрэг дэлгэцийнхээ дээд хэсгийг цэвэрлэнэ үү"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Гэрэлтүүлгийг багасгах"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г ашиглахын тулд дууны түвшнийг ихэсгэх, багасгах түлхүүрийг 3 секундийн турш зэрэг дарна уу"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS хүсэлтийг видео дуудлага болгон өөрчилсөн"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS хүсэлтийг USSD хүсэлт болгон өөрчилсөн"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Шинэ SS хүсэлт болгон өөрчилсөн"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Фишинг сэрэмжлүүлэг"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Ажлын профайл"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Мэдэгдсэн"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Дэлгэх"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Үргэлжлүүлэхийн тулд &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; таны төхөөрөмжийн камерт хандах шаардлагатай."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Асаах"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Мэдрэгчийн нууцлал"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 5f4d5fd..a31951a 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"चेहरा ओळखू शकत नाही. पुन्हा प्रयत्न करा."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"एकाच प्रकारची पोझ देत आहात कृपया तुमची पोझ बदला."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"तुमचे डोके थोडे कमी फिरवा."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"तुमचे डोके थोडे कमी फिरवा."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"तुमचे डोके थोडे कमी फिरवा."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"तुमचा चहेरा लपवणारे काहीही काढून टाका."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ब्लॅक बार सह तुमच्या स्क्रीनची वरची बाजू साफ करा"</string>
@@ -685,10 +686,8 @@
     <string name="permdesc_access_notification_policy" msgid="8538374112403845013">"व्यत्यय आणू नका कॉंफिगरेशन वाचण्यासाठी आणि लिहिण्यासाठी ॲपला अनुमती देते."</string>
     <string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"व्ह्यू परवानगी वापर सुरू करा"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"धारकास अ‍ॅपसाठी परवानगी वापरणे सुरू करण्याची अनुमती देते. सामान्य अ‍ॅप्ससाठी कधीही आवश्यकता नसते."</string>
-    <!-- no translation found for permlab_highSamplingRateSensors (3941068435726317070) -->
-    <skip />
-    <!-- no translation found for permdesc_highSamplingRateSensors (8430061978931155995) -->
-    <skip />
+    <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"उच्च नमुना दराने सेन्सर डेटा अ‍ॅक्सेस करते"</string>
+    <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"ॲपला २०० Hz पेक्षा जास्त दराने सेन्सर डेटाचा नमुना तयार करण्याची अनुमती देते"</string>
     <string name="policylab_limitPassword" msgid="4851829918814422199">"पासवर्ड नियम सेट करा"</string>
     <string name="policydesc_limitPassword" msgid="4105491021115793793">"स्क्रीन लॉक पासवर्ड आणि पिन मध्ये अनुमती दिलेले लांबी आणि वर्ण नियंत्रित करा."</string>
     <string name="policylab_watchLogin" msgid="7599669460083719504">"स्क्रीन अनलॉक प्रयत्नांचे परीक्षण करा"</string>
@@ -1669,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ब्राइटनेस कमी करा"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> वापरण्यासाठी दोन्ही व्हॉल्युम की तीन सेकंद दाबा आणि धरून ठेवा"</string>
@@ -1873,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS विनंती व्हिडिओ कॉलवर बदलली"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS विनंती USSD विनंतीवर बदलली"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"नवीन SS विनंतीवर बदलली"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"फिशिंगशी संबंधित सूचना"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"कार्य प्रोफाईल"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"सूचना दिल्या"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"विस्तृत करा"</string>
@@ -2222,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"पुढे सुरू ठेवण्यासाठी, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; ला तुमच्या डिव्हाइसचा कॅमेरा अ‍ॅक्सेस करण्याची आवश्यकता आहे."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"सुरू करा"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"सेन्सरशी संबंधित गोपनीयतेबाबत सूचना"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 27b1d60..5e5b29f 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Tidak lagi dapat mengecam wajah. Cuba lagi."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Terlalu serupa, sila ubah lagak gaya anda."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Pusingkan kepala anda kurang sedikit."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Pusingkan kepala anda kurang sedikit."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Pusingkan kepala anda kurang sedikit."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Alih keluar apa saja yang melindungi wajah anda."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Bersihkan bahagian atas skrin anda, termasuk bar hitam"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Kurangkan Kecerahan"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Tekan dan tahan kedua-dua kekunci kelantangan selama tiga saat untuk menggunakan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Untuk meneruskan proses, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; memerlukan akses kepada kamera peranti anda."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Hidupkan"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privasi Penderia"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 9e1bd73..137c138 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"မျက်နှာ မမှတ်သားနိုင်တော့ပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"ဆင်တူနေသည်၊ အမူအရာ ပြောင်းပါ။"</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ခေါင်းကို သိပ်မလှည့်ပါနှင့်။"</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"ခေါင်းကို သိပ်မလှည့်ပါနှင့်။"</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ခေါင်းကို သိပ်မလှည့်ပါနှင့်။"</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"သင့်မျက်နှာကို ကွယ်နေသည့်အရာအားလုံး ဖယ်ပါ။"</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"အနက်ရောင်ဘားအပါအဝင် ဖန်သားပြင်ထိပ်ကို သန့်ရှင်းရေး လုပ်ပါ"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"တောက်ပမှုကို လျှော့ခြင်း"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ကို သုံးရန် အသံအတိုးအလျှော့ ခလုတ်နှစ်ခုလုံးကို သုံးစက္ကန့်ကြာ ဖိထားပါ"</string>
@@ -2219,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"ဆက်လက်လုပ်ဆောင်ရန် &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; က သင့်စက်၏ ကင်မရာကို အသုံးပြုခွင့်ရရန် လိုအပ်သည်။"</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ဖွင့်ရန်"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"အာရုံခံကိရိယာ လုံခြုံရေး"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index c846701..de71c39 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Kan ikke gjenkjenne ansiktet lenger. Prøv igjen."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"For likt – endre posituren din."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Vri hodet ditt litt mindre."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Vri hodet ditt litt mindre."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Vri hodet ditt litt mindre."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Fjern alt som skjuler ansiktet ditt."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Rengjør den øverste delen av skjermen, inkludert den svarte linjen"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduser lysstyrken"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Trykk og hold inne begge volumtastene i tre sekunder for å bruke <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS-forespørsel endret til videoanrop"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS-forespørsel endret til USSD-forespørsel"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Endret til ny SS-forespørsel"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Varsel om nettfisking"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Arbeidsprofil"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Varslet"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Vis"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"For å fortsette må &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; ha tilgang til enhetskameraet."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Slå på"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensorpersonvern"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 9af472a..83c03a4 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"अब उप्रान्त अनुहार पहिचान गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"अनुहार उस्तै भयो, कृपया आफ्नो पोज बदल्नुहोस्।"</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"आफ्नो टाउको अलि थोरै घुमाउनुहोस्।"</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"आफ्नो टाउको अलि थोरै घुमाउनुहोस्।"</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"आफ्नो टाउको अलि थोरै घुमाउनुहोस्।"</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"तपाईंको अनुहार लुकाउने सबै कुरा लुकाउनुहोस्।"</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"कालो रङको पट्टीलगायत आफ्नो स्क्रिनको माथिल्लो भाग सफा गर्नुहोस्"</string>
@@ -685,10 +686,8 @@
     <string name="permdesc_access_notification_policy" msgid="8538374112403845013">"बाधा नपुर्याउँनुहोस् कन्फिगरेसन पढ्न र लेख्‍नको लागि एपलाई अनुमति दिनुहोस्।"</string>
     <string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"हेर्ने अनुमतिको प्रयोग सुरु गर्नुहोस्"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"वाहकलाई कुनै एपसम्बन्धी अनुमतिको प्रयोग सुरु गर्न दिन्छ। साधारण एपहरूलाई कहिल्यै आवश्यक नपर्नु पर्ने हो।"</string>
-    <!-- no translation found for permlab_highSamplingRateSensors (3941068435726317070) -->
-    <skip />
-    <!-- no translation found for permdesc_highSamplingRateSensors (8430061978931155995) -->
-    <skip />
+    <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"नमुना लिने उच्च दरमा सेन्सरसम्बन्धी डेटा प्रयोग गर्ने"</string>
+    <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"यो अनुमति दिइएमा एपले २०० हर्जभन्दा बढी दरमा सेन्सरसम्बन्धी डेटाको नमुना लिन सक्छ"</string>
     <string name="policylab_limitPassword" msgid="4851829918814422199">"पासवर्ड नियमहरू मिलाउनुहोस्"</string>
     <string name="policydesc_limitPassword" msgid="4105491021115793793">"स्क्रिन लक पासवर्ड र PIN हरूमा अनुमति दिइएको लम्बाइ र वर्णहरूको नियन्त्रण गर्नुहोस्।"</string>
     <string name="policylab_watchLogin" msgid="7599669460083719504">"मनिटरको स्क्रिन अनलक गर्ने प्रयासहरू"</string>
@@ -1669,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"स्क्रिनको चमक घटाउनुहोस्"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> प्रयोग गर्न दुवै भोल्युम कुञ्जीहरूलाई तीन सेकेन्डसम्म थिचिराख्नुहोस्"</string>
@@ -1873,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS अनुरोधलाई भिडियो कलमा परिवर्तन गरियो"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS अनुरोधलाई USSD अनुरोधमा परिवर्तन गरियो"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"नयाँ SS अनुरोधमा परिवर्तन गरियो"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"फिसिङसम्बन्धी अलर्ट"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"कार्य प्रोफाइल"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"सतर्कता गरियो"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"विस्तृत गर्नुहोस्"</string>
@@ -2222,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"जारी राख्न &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; लाई तपाईंको यन्त्रको क्यामेरा प्रयोग गर्ने अनुमति दिनु पर्ने हुन्छ।"</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"अन गर्नुहोस्"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"सेन्सरसम्बन्धी गोपनीयता"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-night/colors.xml b/core/res/res/values-night/colors.xml
index 29f2b6f..4410e94 100644
--- a/core/res/res/values-night/colors.xml
+++ b/core/res/res/values-night/colors.xml
@@ -26,6 +26,10 @@
 
     <color name="notification_default_color_dark">#ddffffff</color>
 
+    <color name="notification_primary_text_color_current">@color/notification_primary_text_color_dark</color>
+    <color name="notification_secondary_text_color_current">@color/notification_secondary_text_color_dark</color>
+    <color name="notification_default_color_current">@color/notification_default_color_dark</color>
+
     <color name="chooser_row_divider">@color/list_divider_color_dark</color>
     <color name="chooser_gradient_background">@color/loading_gradient_background_color_dark</color>
     <color name="chooser_gradient_highlight">@color/loading_gradient_highlight_color_dark</color>
diff --git a/core/res/res/values-night/values.xml b/core/res/res/values-night/values.xml
index 952cdd0..3fd82b8 100644
--- a/core/res/res/values-night/values.xml
+++ b/core/res/res/values-night/values.xml
@@ -28,9 +28,4 @@
     </style>
 
     <style name="Theme.DeviceDefault.QuickSettings.Dialog" parent="Theme.DeviceDefault.Dialog" />
-
-    <style name="TextAppearance.Material.Notification">
-        <item name="textColor">?attr/textColorPrimary</item>
-        <item name="textSize">@dimen/notification_text_size</item>
-    </style>
 </resources>
\ No newline at end of file
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index d76d32a..e2be98d 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Herkent gezicht niet meer. Probeer het nog eens."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Lijkt te veel op elkaar. Verander je pose."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Draai je hoofd iets minder."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Draai je hoofd iets minder."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Draai je hoofd iets minder."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Zorg dat je gezicht volledig zichtbaar is."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Reinig de bovenkant van je scherm, inclusief de zwarte balk"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Helderheid verlagen"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Volumetoetsen ingedrukt gehouden. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> is ingeschakeld."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Volumetoetsen ingedrukt gehouden. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> uitgeschakeld."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Houd beide volumetoetsen drie seconden ingedrukt om <xliff:g id="SERVICE_NAME">%1$s</xliff:g> te gebruiken"</string>
@@ -2219,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"&lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; heeft toegang tot de camera van je apparaat nodig om door te gaan."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Aanzetten"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensorprivacy"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index f42d8ab..bc76142 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"ଆଉ ମୁହଁ ଚିହ୍ନଟ କରିହେଲା ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"ଅତ୍ୟନ୍ତ ସମପରି, ଦୟାକରି ଆପଣଙ୍କର ପୋଜ୍ ବଦଳାନ୍ତୁ।"</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ଆପଣଙ୍କର ମୁଣ୍ଡକୁ ଟିକିଏ ବୁଲାନ୍ତୁ।"</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"ଆପଣଙ୍କର ମୁଣ୍ଡକୁ ଟିକିଏ ବୁଲାନ୍ତୁ।"</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ଆପଣଙ୍କର ମୁଣ୍ଡକୁ ଟିକିଏ ବୁଲାନ୍ତୁ।"</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"ଆପଣଙ୍କର ମୁହଁ ଲୁଚାଉଥିବା ଜିନିଷକୁ କାଢ଼ି ଦିଅନ୍ତୁ।"</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"କଳା ବାର୍ ସମେତ ଆପଣଙ୍କ ସ୍କ୍ରିନ୍‌ର ଶୀର୍ଷକୁ ସଫା କରନ୍ତୁ"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ଉଜ୍ଜ୍ୱଳତା କମାନ୍ତୁ"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ବ୍ୟବହାର କରିବାକୁ ତିନି ସେକେଣ୍ଡ ପାଇଁ ଉଭୟ ଭଲ୍ୟୁମ୍‍ କୀ ଦବାଇ ଧରି ରଖନ୍ତୁ"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SSଙ୍କ ଅନୁରୋଧକୁ ଭିଡିଓ କଲ୍‌ରେ ପରିବର୍ତ୍ତନ କରାଗଲା"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS ଅନୁରୋଧ, USSD ଅନୁରୋଧକୁ ପରିବର୍ତ୍ତନ ହେଲା"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"ନୂତନ SS ଅନୁରୋଧରେ ପରିବର୍ତ୍ତନ ହେଲା"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ଫିସିଂ ଆଲର୍ଟ"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"ୱର୍କ ପ୍ରୋଫାଇଲ୍‌"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"ଆଲର୍ଟ କରାଯାଇଛି"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"ବଢ଼ାନ୍ତୁ"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"ଜାରି ରଖିବାକୁ, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; ଆପଣଙ୍କ ଡିଭାଇସର କ୍ୟାମେରାକୁ ଆକ୍ସେସ୍ ଆବଶ୍ୟକ କରେ।"</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ଚାଲୁ କରନ୍ତୁ"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"ସେନ୍ସର୍ ଗୋପନୀୟତା"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 17a4944..c9f57ef 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"ਹੁਣ ਚਿਹਰਾ ਪਛਾਣਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"ਬਹੁਤ ਮਿਲਦਾ-ਜੁਲਦਾ ਹੈ, ਕਿਰਪਾ ਕਰਕੇ ਆਪਣਾ ਅੰਦਾਜ਼ ਬਦਲੋ।"</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ਆਪਣਾ ਸਿਰ ਥੋੜਾ ਜਿਹਾ ਝੁਕਾਓ।"</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"ਆਪਣਾ ਸਿਰ ਥੋੜਾ ਜਿਹਾ ਝੁਕਾਓ।"</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ਆਪਣਾ ਸਿਰ ਥੋੜਾ ਜਿਹਾ ਝੁਕਾਓ।"</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"ਤੁਹਾਡਾ ਚਿਹਰਾ ਲੁਕਾਉਣ ਵਾਲੀ ਕੋਈ ਵੀ ਚੀਜ਼ ਹਟਾਓ।"</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ਕਾਲੀ ਪੱਟੀ ਸਮੇਤ, ਆਪਣੀ ਸਕ੍ਰੀਨ ਦੇ ਸਿਖਰ ਨੂੰ ਸਾਫ਼ ਕਰੋ"</string>
@@ -685,10 +686,8 @@
     <string name="permdesc_access_notification_policy" msgid="8538374112403845013">"ਐਪ ਨੂੰ ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ ਕੌਂਫਿਗਰੇਸ਼ਨ ਨੂੰ ਪੜ੍ਹਨ ਅਤੇ ਲਿਖਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
     <string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"ਇਜਾਜ਼ਤ ਵਰਤੋਂ ਦੇਖਣਾ ਸ਼ੁਰੂ ਕਰੋ"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"ਧਾਰਕ ਨੂੰ ਕਿਸੇ ਹੋਰ ਐਪ ਲਈ ਇਜਾਜ਼ਤ ਵਰਤੋਂ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਦਿੰਦਾ ਹੈ। ਸਧਾਰਨ ਐਪਾਂ ਲਈ ਕਦੇ ਵੀ ਲੋੜੀਂਦਾ ਨਹੀਂ ਹੋਵੇਗਾ।"</string>
-    <!-- no translation found for permlab_highSamplingRateSensors (3941068435726317070) -->
-    <skip />
-    <!-- no translation found for permdesc_highSamplingRateSensors (8430061978931155995) -->
-    <skip />
+    <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"ਉੱਚ ਸੈਂਪਲਿੰਗ ਰੇਟ \'ਤੇ ਸੈਂਸਰ ਡਾਟਾ ਤੱਕ ਪਹੁੰਚ ਕਰੋ"</string>
+    <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"ਐਪ ਨੂੰ 200 Hz ਤੋਂ ਵੱਧ ਦੀ ਦਰ \'ਤੇ ਸੈਂਸਰ ਡਾਟੇ ਦਾ ਨਮੂਨਾ ਲੈਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ"</string>
     <string name="policylab_limitPassword" msgid="4851829918814422199">"ਪਾਸਵਰਡ ਨਿਯਮ ਸੈੱਟ ਕਰੋ"</string>
     <string name="policydesc_limitPassword" msgid="4105491021115793793">"ਸਕ੍ਰੀਨ ਲਾਕ ਪਾਸਵਰਡਾਂ ਅਤੇ ਪਿੰਨ ਵਿੱਚ ਆਗਿਆ ਦਿੱਤੀ ਲੰਮਾਈ ਅਤੇ ਅੱਖਰਾਂ ਤੇ ਨਿਯੰਤਰਣ ਪਾਓ।"</string>
     <string name="policylab_watchLogin" msgid="7599669460083719504">"ਸਕ੍ਰੀਨ ਅਣਲਾਕ ਕਰਨ ਦੀਆਂ ਕੋਸ਼ਿਸ਼ਾਂ \'ਤੇ ਨਿਗਰਾਨੀ ਰੱਖੋ"</string>
@@ -1669,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ਚਮਕ ਘਟਾਓ"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ ਦੋਵੇਂ ਅਵਾਜ਼ ਕੁੰਜੀਆਂ ਨੂੰ 3 ਸਕਿੰਟਾਂ ਲਈ ਦਬਾਈ ਰੱਖੋ"</string>
@@ -1873,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS ਬੇਨਤੀ ਨੂੰ ਵੀਡੀਓ ਕਾਲ ਵਿੱਚ ਬਦਲਿਆ ਗਿਆ"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS ਬੇਨਤੀ ਨੂੰ USSD ਬੇਨਤੀ ਵਿੱਚ ਬਦਲਿਆ ਗਿਆ"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"ਨਵੀਂ SS ਬੇਨਤੀ ਵਿੱਚ ਬਦਲਿਆ ਗਿਆ"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ਫ਼ਿਸ਼ਿੰਗ ਸੰਬੰਧੀ ਸੁਚੇਤਨਾ"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"ਸੁਚੇਤਨਾਵਾਂ"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"ਵਿਸਤਾਰ ਕਰੋ"</string>
@@ -2222,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"ਜਾਰੀ ਰੱਖਣ ਲਈ, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; ਨੂੰ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੇ ਕੈਮਰਾ ਤੱਕ ਪਹੁੰਚ ਦੀ ਲੋੜ ਹੈ।"</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ਚਾਲੂ ਕਰੋ"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"ਸੈਂਸਰ ਪਰਦੇਦਾਰੀ"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 14ca2b9..6c12366 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -612,7 +612,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Nie można już rozpoznać twarzy. Spróbuj ponownie."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Za mała różnica. Zmień pozycję."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Trochę mniej obróć głowę."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Trochę mniej obróć głowę."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Trochę mniej obróć głowę."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Usuń wszystko, co zasłania Ci twarz."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Wyczyść górną krawędź ekranu, w tym czarny pasek"</string>
@@ -1711,7 +1712,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Zmniejsz jasność"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Naciśnij i przytrzymaj oba przyciski głośności przez trzy sekundy, by użyć usługi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1933,8 +1935,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Żądanie SS zmienione na rozmowę wideo"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Żądanie SS zmienione na żądanie USSD"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Zmieniono na nowe żądanie SS"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alert o phishingu"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profil służbowy"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Alert"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Rozwiń"</string>
@@ -2288,4 +2289,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Aby kontynuować, musisz przyznać aplikacji „<xliff:g id="APP">%s</xliff:g>” dostęp do aparatu urządzenia."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Włącz"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Poufność danych z czujników"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 3fbfd7e..d5cec26 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"O rosto não é mais reconhecido. Tente novamente."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Muito parecido, mude de posição."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Incline a cabeça um pouco menos."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Incline a cabeça um pouco menos."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Incline a cabeça um pouco menos."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Remova tudo que esteja ocultando seu rosto."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Limpe a parte superior da tela, inclusive a barra preta"</string>
@@ -867,7 +868,7 @@
     <string name="lockscreen_transport_pause_description" msgid="6705284702135372494">"Pausar"</string>
     <string name="lockscreen_transport_play_description" msgid="106868788691652733">"Reproduzir"</string>
     <string name="lockscreen_transport_stop_description" msgid="1449552232598355348">"Parar"</string>
-    <string name="lockscreen_transport_rew_description" msgid="7680106856221622779">"Retroceder"</string>
+    <string name="lockscreen_transport_rew_description" msgid="7680106856221622779">"Voltar"</string>
     <string name="lockscreen_transport_ffw_description" msgid="4763794746640196772">"Avançar"</string>
     <string name="emergency_calls_only" msgid="3057351206678279851">"Só chamadas de emergência"</string>
     <string name="lockscreen_network_locked_message" msgid="2814046965899249635">"Rede bloqueada"</string>
@@ -1667,7 +1668,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Usar atalho"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversão de cores"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Correção de cor"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduzir brilho"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas de volume pressionadas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ativado."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume pressionadas. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desativado."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Toque nos dois botões de volume e os mantenha pressionados por três segundo para usar o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Para continuar, o app &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; precisa acessar a câmera do dispositivo."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Ativar"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privacidade do sensor"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index eb09af8..6867950 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Impossível reconhecer o rosto. Tente novamente."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Muito parecida, mude de pose."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Rode a cabeça um pouco menos."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Rode a cabeça um pouco menos."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Rode a cabeça um pouco menos."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Remova tudo o que esteja a ocultar o seu rosto."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Limpe a parte superior do ecrã, incluindo a barra preta."</string>
@@ -1667,7 +1668,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utilizar atalho"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversão de cores"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Correção da cor"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduzir o brilho"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas do volume premidas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ativado."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume premidas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desativado."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Prima sem soltar as teclas de volume durante três segundos para utilizar o serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"O pedido SS foi alterado para uma videochamada."</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"O pedido SS foi alterado para um novo pedido USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Foi alterado para um novo pedido SS."</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerta de phishing."</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Perfil de trabalho"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Alertado"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Expandir"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Para continuar, a app &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; precisa de acesso à câmara do dispositivo."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Ativar"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privacidade dos sensores"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index bad102e..d5cec26 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"O rosto não é mais reconhecido. Tente novamente."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Muito parecido, mude de posição."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Incline a cabeça um pouco menos."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Incline a cabeça um pouco menos."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Incline a cabeça um pouco menos."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Remova tudo que esteja ocultando seu rosto."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Limpe a parte superior da tela, inclusive a barra preta"</string>
@@ -867,7 +868,7 @@
     <string name="lockscreen_transport_pause_description" msgid="6705284702135372494">"Pausar"</string>
     <string name="lockscreen_transport_play_description" msgid="106868788691652733">"Reproduzir"</string>
     <string name="lockscreen_transport_stop_description" msgid="1449552232598355348">"Parar"</string>
-    <string name="lockscreen_transport_rew_description" msgid="7680106856221622779">"Retroceder"</string>
+    <string name="lockscreen_transport_rew_description" msgid="7680106856221622779">"Voltar"</string>
     <string name="lockscreen_transport_ffw_description" msgid="4763794746640196772">"Avançar"</string>
     <string name="emergency_calls_only" msgid="3057351206678279851">"Só chamadas de emergência"</string>
     <string name="lockscreen_network_locked_message" msgid="2814046965899249635">"Rede bloqueada"</string>
@@ -1667,7 +1668,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Usar atalho"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversão de cores"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Correção de cor"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduzir brilho"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas de volume pressionadas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ativado."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume pressionadas. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desativado."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Toque nos dois botões de volume e os mantenha pressionados por três segundo para usar o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Solicitação SS alterada para videochamada"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Solicitação SS alterada para solicitação USSD"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Alterada para uma nova solicitação SS"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerta de phishing"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Perfil de trabalho"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Alertado"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Expandir"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Para continuar, o app &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; precisa acessar a câmera do dispositivo."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Ativar"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privacidade do sensor"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 1e789e4..690884a 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -609,7 +609,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Nu se mai poate recunoaște fața. Încercați din nou."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Prea asemănător, schimbați poziția."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Întoarceți capul mai puțin."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Întoarceți capul mai puțin."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Întoarceți capul mai puțin."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Eliminați orice vă ascunde chipul."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Curățați partea de sus a ecranului, inclusiv bara neagră"</string>
@@ -1689,7 +1690,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utilizați comanda rapidă"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversarea culorilor"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Corecția culorii"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduceți luminozitatea"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"S-au apăsat lung tastele de volum. S-a activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"S-au apăsat lung tastele de volum. S-a dezactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Apăsați ambele butoane de volum timp de trei secunde pentru a folosi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2253,4 +2255,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Pentru a continua, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; necesită acces la camera dispozitivului."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Activați"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Confidențialitatea privind senzorii"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 5cb8a50..84752d5 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -612,7 +612,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Не удалось распознать лицо. Повторите попытку."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Слишком похожее выражение лица. Измените позу."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Держите голову ровнее."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Держите голову ровнее."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Держите голову ровнее."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Ваше лицо плохо видно."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Протрите верхнюю часть экрана (в том числе черную панель)."</string>
@@ -1711,7 +1712,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Уменьшение яркости"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Чтобы использовать сервис \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\", нажмите и удерживайте обе клавиши громкости в течение трех секунд."</string>
@@ -1933,8 +1935,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS-запрос преобразован в видеовызов"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS-запрос преобразован в USSD-запрос"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Преобразовано в SS-запрос"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Предупреждение о фишинге"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Рабочий профиль"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Отправлено оповещение"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Развернуть"</string>
@@ -2288,4 +2289,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Чтобы продолжить, предоставьте приложению &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; доступ к камере устройства."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Включить"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Конфиденциальность датчиков"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index bd311fb9..66547de 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"තවදුරටත් මුහුණ හඳුනාගත නොහැක. නැවත උත්සාහ කරන්න."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"ඉතා සමානයි, ඔබේ හැඩ ගැසීම වෙනස් කරන්න."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ඔබේ හිස ටිකක් අඩුවෙන් කරකවන්න."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"ඔබේ හිස ටිකක් අඩුවෙන් කරකවන්න."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ඔබේ හිස ටිකක් අඩුවෙන් කරකවන්න."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"ඔබේ මුහුණ සඟවන කිසිවක් ඉවත් කරන්න."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"කලු තීරුව ඇතුළුව, ඔබේ තිරයෙහි මුදුන පිරිසිදු කරන්න"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"දීප්තිය අඩු කරන්න"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> භාවිත කිරීමට හඬ පරිමා යතුරු දෙකම තත්පර තුනකට ඔබාගෙන සිටින්න"</string>
@@ -2219,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"දිගටම කර ගෙන යාමට, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; හට ඔබගේ උපාංගයෙහි කැමරාවට ප්‍රවේශය අවශ්‍යයි."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ක්‍රියාත්මක කරන්න"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"සංවේදක පෞද්ගලිකත්වය"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 825215b..487b818 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -612,7 +612,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Tvár už nie je možné rozpoznať. Skúste to znova."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Príliš rovnaké, zmeňte postoj."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Otočte hlavu o niečo menej."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Otočte hlavu o niečo menej."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Otočte hlavu o niečo menej."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Odstráňte všetko, čo vám zakrýva tvár."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Vyčistite hornú časť obrazovky vrátane čierneho panela"</string>
@@ -1711,7 +1712,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Použiť skratku"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Inverzia farieb"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Úprava farieb"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Zníženie jasu"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Pridržali ste tlačidlá hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je zapnutá."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Pridržali ste tlačidlá hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je vypnutá."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Ak chcete používať službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, pridržte tri sekundy oba klávesy hlasitosti"</string>
@@ -1933,8 +1935,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Žiadosť SS bola zmenená na videohovor"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Žiadosť SS bola zmenená na žiadosť USSD"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Zmenené na novú žiadosť SS"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Upozornenie na phishing"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Pracovný profil"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Upozornené"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Rozbaliť"</string>
@@ -2288,4 +2289,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Ak chcete pokračovať, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; požaduje prístup k fotoaparátu zariadenia."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Zapnúť"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Ochrana súkromia senzorov"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index a27b805..87a66b3 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -612,7 +612,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Obraza ni več mogoče prepoznati. Poskusite znova."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Preveč podobno, spremenite položaj."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Glejte malce bolj naravnost."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Malce manj nagnite glavo."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Glejte malce bolj naravnost."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Umaknite vse, kar vam morda zakriva obraz."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Očistite vrhnji del zaslona, vključno s črno vrstico"</string>
@@ -1711,7 +1712,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Uporabi bližnjico"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Inverzija barv"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Popravljanje barv"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Zmanjšanje svetlosti"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tipki za glasnost sta pridržani. Storitev <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je vklopljena."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tipki za glasnost sta pridržani. Storitev <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je izklopljena."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Za uporabo storitve <xliff:g id="SERVICE_NAME">%1$s</xliff:g> pritisnite obe tipki za glasnost in ju pridržite tri sekunde"</string>
@@ -2287,4 +2289,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Za nadaljevanje potrebuje aplikacija &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; dostop do fotoaparata v napravi."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Vklopi"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Zasebnost pri uporabi tipal"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 823b963..4c37424 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Fytyra nuk mund të njihet më. Provo përsëri."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Tepër e ngjashme, ndrysho pozën"</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Ktheje kokën pak më pak."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Ktheje kokën pak më pak."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Ktheje kokën pak më pak."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Hiq gjithçka që fsheh fytyrën tënde."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Pastro kreun e ekranit, duke përfshirë shiritin e zi"</string>
@@ -1667,7 +1668,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Përdor shkurtoren"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Kthimi i ngjyrës"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Korrigjimi i ngjyrës"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Redukto ndriçimin"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tastet e volumit të mbajtura shtypur. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> i aktivizuar."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tastet e volumit të mbajtura shtypur. U çaktivizua \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\"."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Shtyp dhe mbaj shtypur të dy butonat e volumit për tre sekonda për të përdorur <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Kërkesa SS u ndryshua në telefonatë me video"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Kërkesa SS u ndryshua në kërkesë USSD"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"U ndryshua në kërkesë të re SS"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Sinjalizim për mashtrim"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profili i punës"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Sinjalizuar"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Zgjero"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Për të vazhduar, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; ka nevojë të qaset në kamerën e pajisjes sate."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Aktivizo"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privatësia e sensorit"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 74589a8..d061d6f 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -609,7 +609,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Више не може да се препозна лице. Пробајте поново."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Превише је слично, промените позу."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Мало мање померите главу."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Мало мање померите главу."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Мало мање померите главу."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Уклоните све што вам заклања лице."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Очистите горњи део екрана, укључујући црну траку"</string>
@@ -1689,7 +1690,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Смањите осветљеност"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Притисните и задржите оба тастера за јачину звука три секунде да бисте користили <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2253,4 +2255,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"&lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; захтева приступ камери уређаја ради настављања."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Укључи"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Приватност сензора"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 47bfe0a..8288d41 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Ansiktet kan inte längre kännas igen. Försök igen."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"För likt. Ändra ansiktsposition."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Vrid mindre på huvudet."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Vrid mindre på huvudet."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Vrid mindre på huvudet."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Ta bort allt som täcker ansiktet."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Rengör skärmens överkant, inklusive det svarta fältet"</string>
@@ -1667,7 +1668,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Använd kortkommandot"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Inverterade färger"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Färgkorrigering"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Minska ljusstyrkan"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Volymknapparna har tryckts ned. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> har aktiverats."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Volymknapparna har tryckts ned. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> har inaktiverats."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Tryck och håll båda volymknapparna i tre sekunder för att använda <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS-begäran har ändrats till videosamtal"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS-begäran har ändrats till en USSD-begäran"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Har ändrats till ny SS-begäran"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Varning om nätfiske"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Jobbprofil"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Aviserad"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Utöka"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"&lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; behöver behörighet till enhetens kamera för att fortsätta."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Aktivera"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensorintegritet"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index fcc9c9d..6ac7d2a 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Haiwezi tena kutambua uso. Jaribu tena."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Inafanana sana, tafadhali badilisha mkao wako."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Geuza kichwa chako kidogo."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Geuza kichwa chako kidogo."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Geuza kichwa chako kidogo."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Ondoa kitu chochote kinachoficha uso wako."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Safisha sehemu ya juu ya skrini yako, ikiwa ni pamoja na upau mweusi"</string>
@@ -1667,7 +1668,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Tumia Njia ya Mkato"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Ugeuzaji rangi"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Usahihishaji wa rangi"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Punguza Ung\'aavu"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Vitufe vya sauti vilivyoshikiliwa. Umewasha <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Vitufe vya sauti vimeshikiliwa. Umezima <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Bonyeza na ushikilie vitufe vyote viwili vya sauti kwa sekunde tatu ili utumie <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Ili uendelee, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; inahitaji ruhusa ya kufikia kamera ya kifaa chako."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Washa"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Faragha ya Kitambuzi"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 535fb6c..1ac1734 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"முகத்தைக் கண்டறிய இயலவில்லை. மீண்டும் முயலவும்."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"மீண்டும் அதே போஸ் தருகிறீர்கள், வேறு முயலுங்கள்."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"தலையை லேசாகத் திருப்பவும்."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"தலையை லேசாகத் திருப்பவும்."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"உங்கள் தலையைச் சற்றுத் திருப்பவும்."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"உங்கள் முகத்தை மறைக்கும் அனைத்தையும் நீக்குக."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"திரையையும் அதிலுள்ள கருப்புப் பட்டியையும் சுத்தம் செய்யவும்"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ஒளிர்வைக் குறைத்தல்"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ஐப் பயன்படுத்த 3 விநாடிகளுக்கு இரண்டு ஒலியளவு பட்டன்களையும் அழுத்திப் பிடிக்கவும்"</string>
@@ -2219,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"தொடர, உங்கள் சாதனத்தின் கேமராவை அணுகுவதற்கு &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; ஆப்ஸுக்கு அனுமதி வேண்டும்."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ஆன் செய்"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"சென்சார் தனியுரிமை"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 59d451a..9f822e3 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"ఇక ముఖం గుర్తించలేదు. మళ్లీ ప్రయత్నించండి."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"ఒకే మాదిరిగా ఉంది, దయచేసి భంగిమను మార్చండి."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"మీ తలను ఇంకాస్త తక్కువ తిప్పండి."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"మీ తలను ఇంకాస్త తక్కువ తిప్పండి."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"మీ తలను ఎడమ/కుడి వైపుగా ఇంకాస్త తిప్పండి."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"మీ ముఖానికి అడ్డుగా ఉన్నవాటిని తీసివేస్తుంది."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"నల్లని పట్టీతో సహా మీ స్క్రీన్ పైభాగం అంతటినీ శుభ్రంగా తుడవండి"</string>
@@ -685,10 +686,8 @@
     <string name="permdesc_access_notification_policy" msgid="8538374112403845013">"అంతరాయం కలిగించవద్దు ఎంపిక కాన్ఫిగరేషన్ చదవడానికి మరియు వ్రాయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"వీక్షణ అనుమతి వినియోగాన్ని ప్రారంభించండి"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"యాప్‌నకు అనుమతి వినియోగాన్ని ప్రారంభించడానికి హోల్డర్‌‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ ఇటువంటి అనుమతి అవసరం ఉండదు."</string>
-    <!-- no translation found for permlab_highSamplingRateSensors (3941068435726317070) -->
-    <skip />
-    <!-- no translation found for permdesc_highSamplingRateSensors (8430061978931155995) -->
-    <skip />
+    <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"అధిక శాంపిల్ రేటు వద్ద సెన్సార్ డేటాను యాక్సెస్ చేయండి"</string>
+    <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"200 Hz కంటే ఎక్కువ రేట్ వద్ద శాంపిల్ సెన్సార్ డేటాకు యాప్‌ను అనుమతిస్తుంది"</string>
     <string name="policylab_limitPassword" msgid="4851829918814422199">"పాస్‌వర్డ్ నియమాలను సెట్ చేయండి"</string>
     <string name="policydesc_limitPassword" msgid="4105491021115793793">"స్క్రీన్ లాక్ పాస్‌వర్డ్‌లు మరియు PINల్లో అనుమతించబడిన పొడవు మరియు అక్షరాలను నియంత్రిస్తుంది."</string>
     <string name="policylab_watchLogin" msgid="7599669460083719504">"స్క్రీన్ అన్‌లాక్ ప్రయత్నాలను పర్యవేక్షించండి"</string>
@@ -1669,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ప్రకాశాన్ని తగ్గించండి"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ని ఉపయోగించడానికి వాల్యూమ్ కీలు రెండింటినీ 3 సెకన్లు నొక్కి ఉంచండి"</string>
@@ -2221,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"కొనసాగించడానికి, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&amp;gtకు మీ పరికరం యొక్క కెమెరా యాక్సెస్ అవసరం."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ఆన్ చేయి"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"సెన్సార్ గోప్యత"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index cb21c72..21865cd 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"จำใบหน้าไม่ได้แล้ว ลองอีกครั้ง"</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"ใกล้เคียงเกินไป โปรดเปลี่ยนท่าโพส"</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"จัดตำแหน่งศีรษะให้ตรง"</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"จัดตำแหน่งศีรษะให้ตรง"</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"จัดตำแหน่งศีรษะให้ตรง"</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"เอาสิ่งที่ปิดบังใบหน้าออก"</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ทำความสะอาดด้านบนของหน้าจอ รวมถึงแถบสีดำ"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ลดความสว่าง"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"กดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มค้างไว้ 3 วินาทีเพื่อใช้ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"&lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; ต้องได้รับสิทธิ์เข้าถึงกล้องของอุปกรณ์เพื่อดำเนินการต่อ"</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"เปิด"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"ความเป็นส่วนตัวสำหรับเซ็นเซอร์"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 6f00ba8..37d06f8 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Hindi na makilala ang mukha. Subukang muli."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Masyadong magkatulad, pakibago ang pose mo."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Huwag masyadong lumingon."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Huwag masyadong tumingala o yumuko."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Huwag masyadong lumingon."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Alisin ang anumang humaharang sa iyong mukha."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Linisin ang itaas ng iyong screen, kasama ang itim na bar"</string>
@@ -1667,7 +1668,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Gamitin ang Shortcut"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Pag-invert ng Kulay"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Pagwawasto ng Kulay"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Bawasan ang Liwanag"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Pinindot nang matagal ang volume keys. Na-on ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Pinindot nang matagal ang volume keys. Na-off ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Pindutin nang matagal ang parehong volume key sa loob ng tatlong segundo para magamit ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Ginawang video call ang SS na kahilingan"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Ginawang USSD na kahilingan ang SS na kahilingan"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Ginawang bagong SS na kahilingan"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerto sa phishing"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profile sa trabaho"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Naalertuhan"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Palawakin"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Para magpatuloy, kailangan ng &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; ng access sa camera ng iyong device."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"I-on"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privacy ng Sensor"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 67086d2..2132aac 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Yüz artık tanınamıyor. Tekrar deneyin."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Duruşunuz çok benzer, lütfen pozunuzu değiştirin."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Başınızı biraz daha az çevirin."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Başınızı biraz daha az çevirin."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Başınızı biraz daha az çevirin."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Yüzünüzün görünmesini engelleyen şeyleri kaldırın."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Siyah çubuk da dahil olmak üzere ekranınızın üst kısmını temizleyin"</string>
@@ -1667,7 +1668,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Kısayolu Kullan"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Rengi Ters Çevirme"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Renk Düzeltme"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Parlaklığı Azaltma"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Ses tuşlarını basılı tuttunuz. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> açıldı."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Ses tuşlarını basılı tuttunuz. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> kapatıldı."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> hizmetini kullanmak için her iki ses tuşunu basılı tutun"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS isteği görüntülü görüşme olarak değişti"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS isteği USSD isteği olarak değişti"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Yeni SS isteği olarak değişti"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Kimlik avı uyarısı"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"İş profili"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Sesli uyarıldı"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Genişlet"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Devam etmek için &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; uygulamasının cihazınızın kamerasına erişmesi gerekiyor."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Aç"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensör Gizliliği"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index d6a3677..3b9db40 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -612,7 +612,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Розпізнати обличчя вже не вдається. Повторіть спробу."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Надто схоже на попередню спробу, змініть позу."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Трохи перемістіть обличчя."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Трохи перемістіть обличчя."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Трохи поверніть обличчя."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Приберіть об’єкти, які затуляють ваше обличчя."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Очистьте верхню частину екрана, зокрема чорну панель"</string>
@@ -1711,7 +1712,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Зменшення яскравості"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Щоб скористатися службою <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, утримуйте обидві клавіші гучності впродовж трьох секунд"</string>
@@ -1933,8 +1935,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Запит SS змінено на відеовиклик"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Запит SS змінено на запит USSD"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Змінено на новий запит SS"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Попередження про фішинг"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Робочий профіль"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Зі звуком"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Розгорнути"</string>
@@ -2288,4 +2289,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Щоб продовжити, надайте додатку &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; доступ до камери пристрою."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Увімкнути"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Конфіденційність датчиків"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 9a7cb87..c10f3e9 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"اب چہرے کی شناخت نہیں کر سکتے۔ پھر آزمائيں۔"</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"کافی ملتا جلتا ہے، براہ کرم اپنا پوز بدلیں۔"</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"اپنا سر تھوڑا کم کریں۔"</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"اپنا سر تھوڑا کم کریں۔"</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"اپنا سر تھوڑا کم کریں۔"</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"آپ کے چہرہ کو چھپانے والی ہر چیز کو ہٹائیں۔"</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"سیاہ بار سمیت، اپنی اسکرین کے اوپری حصے کو صاف کریں"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"چمک کم کریں"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> کا استعمال کرنے کے لیے 3 سیکنڈ تک والیوم کی دونوں کلیدوں کو چھوئیں اور دبائے رکھیں"</string>
@@ -2219,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"‏جاری رکھنے کیلئے ‎&lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt;‎ کو آپ کے آلے کے کیمرے تک رسائی درکار ہے۔"</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"آن کریں"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"سینسر کی رازداری"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 60134a47..f77de7d 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -606,7 +606,7 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Yuz tanilmadi. Qaytadan urining."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Yuz ifodasi oldingiday. Holatingizni oʻzgartiring."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Boshingizni asta buring."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Boshingizni asta buring."</string>
+    <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Boshingizni asta qiyalang."</string>
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Boshingizni asta buring."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Yuzingizni berkitayotgan narsalarni olib tashlang."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Ekranning yuqori qismini, shuningdek, qora panelni ham tozalang"</string>
@@ -1667,7 +1667,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Tezkor ishga tushirishdan foydalanish"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Ranglarni akslantirish"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Rangni tuzatish"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Yorqinlikni pasaytirish"</string>
+    <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Yorqinlikni pasaytirish"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tovush tugmalari bosib turildi. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> yoqildi."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tovush tugmalari bosib turildi. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> faolsizlantirildi."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> xizmatidan foydalanish uchun ikkala ovoz balandligi tugmalarini uzoq bosib turing"</string>
@@ -1871,8 +1871,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"SS talabi video chaqiruvga almashtirildi"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"SS talabi USSD talabiga almashtirildi"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Yangi SS talabiga almashtirildi"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Fishing signali"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Ish profili"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Ogohlantirildi"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Yoyish"</string>
@@ -2220,4 +2219,6 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Davom etish uchun &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; qurilmangiz kamerasiga kirishi kerak."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Yoqish"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensorlar maxfiyligi"</string>
+    <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Ilova belgisi"</string>
+    <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Ilova brendining rasmi"</string>
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 25f0644..baf0b86d 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Không nhận ra khuôn mặt. Hãy thử lại."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Khuôn mặt quá giống nhau, vui lòng đổi tư thế."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Hãy bớt di chuyển đầu."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Hãy bớt di chuyển đầu."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Hãy bớt di chuyển đầu."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Hãy loại bỏ mọi thứ che khuất khuôn mặt bạn."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Vệ sinh phần đầu màn hình, bao gồm cả thanh màu đen"</string>
@@ -1667,7 +1668,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Sử dụng phím tắt"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Đảo màu"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Chỉnh màu"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Giảm độ sáng"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Bạn đã giữ các phím âm lượng. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> đã bật."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Bạn đã giữ các phím âm lượng. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> đã tắt."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Nhấn và giữ đồng thời cả hai phím âm lượng trong 3 giây để sử dụng <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Yêu cầu SS đã thay đổi thành cuộc gọi video"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Yêu cầu SS đã thay đổi thành yêu cầu USSD"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Đã thay đổi thành yêu cầu SS mới"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Cảnh báo về hành vi lừa đảo"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Hồ sơ công việc"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Đã phát âm báo"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Mở rộng"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Để tiếp tục, &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; cần quyền truy cập vào máy ảnh trên thiết bị của bạn."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Bật"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Quyền riêng tư khi sử dụng cảm biến"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 358367e..9345fc82 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"已无法识别人脸,请重试。"</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"与先前的姿势太相近,请换一个姿势。"</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"请将您的头稍微上下倾斜。"</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"请将您的头稍微上下倾斜。"</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"请将您的头稍微左右旋转。"</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"请移除所有遮挡您面部的物体。"</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"请将屏幕顶部(包括黑色条栏)清理干净"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"调低亮度"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"同时按住两个音量键 3 秒钟即可使用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"如要继续操作,请向&lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt;授予设备的相机使用权。"</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"开启"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"传感器隐私权"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index e4fa2e0..1187f00 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"無法再識別臉孔。請再試一次。"</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"臉孔位置太相近,請改變您的姿勢。"</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"減少頭部左右轉動幅度。"</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"減少頭部上下轉動幅度。"</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"減少頭部左右轉動幅度。"</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"移除遮住您臉孔的任何東西。"</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"請清理螢幕頂部,包括黑色列"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"調低亮度"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"㩒住兩個音量鍵 3 秒就可以用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -2219,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"如要繼續,&lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; 需要裝置的相機存取權。"</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"開啟"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"感應器私隱"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 49e57b3..9492572 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"已無法辨識臉孔,請再試一次。"</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"與先前的姿勢太相似,請換一個姿勢。"</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"請將你的頭部稍微向左或向右轉動。"</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"請將你的頭部稍微向上或向下傾斜。"</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"請將你的頭部稍微向左或向右旋轉。"</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"請移除任何會遮住臉孔的物體。"</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"請清理螢幕頂端,包括黑色橫列"</string>
@@ -1667,7 +1668,8 @@
     <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>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"調低亮度"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <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>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"同時按住調低及調高音量鍵三秒即可使用「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」"</string>
@@ -2219,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"如要繼續操作,請將裝置的相機存取權授予「<xliff:g id="APP">%s</xliff:g>」&lt;b&gt;&lt;/b&gt;。"</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"開啟"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"感應器隱私權"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 9a21e78..e5a026bd 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -606,7 +606,8 @@
     <string name="face_acquired_too_different" msgid="4699657338753282542">"Ayisakwazi ukubona ubuso. Zama futhi."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Kufana kakhulu, sicela ushintshe ukuma kwakho."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Jikisa ikhanda lakho kancane."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Jikisa ikhanda lakho kancane."</string>
+    <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
+    <skip />
     <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Jikisa ikhanda lakho kancane."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"Susa noma yini efihle ubuso bakho."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Hlanza okuphezulu kwesikrini sakho, kufaka phakathi ibha emnyama"</string>
@@ -1667,7 +1668,8 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Sebenzisa isinqamuleli"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Ukuguqulwa kombala"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Ukulungiswa kombala"</string>
-    <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Nciphisa ukukhanya"</string>
+    <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
+    <skip />
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Ubambe okhiye bevolumu. I-<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ivuliwe."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Ubambe okhiye bevolumu. I-<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ivaliwe."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Cindezela uphinde ubambe bobabili okhiye bevolumu ngamasekhondi amathathu ukuze usebenzise i-<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1871,8 +1873,7 @@
     <string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Isicelo se-SS sishintshele kukholi yevidiyo"</string>
     <string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Isicelo se-SS sishintshele kusicelo se-USSD"</string>
     <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Ishintshele kusicelo esisha se-SS"</string>
-    <!-- no translation found for notification_phishing_alert_content_description (494227305355958790) -->
-    <skip />
+    <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Isexwayiso sobugebengu bokweba imininingwane ebucayi"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Iphrofayela yomsebenzi"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Kuxwayisiwe"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Nweba"</string>
@@ -2220,4 +2221,8 @@
     <string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Ukuze uqhubeke, &lt;b&gt;i-<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; idinga ukufinyelela ikhamera yakho."</string>
     <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Vula"</string>
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Ubumfihlo Benzwa"</string>
+    <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
+    <skip />
+    <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 735e1224..100983b 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3564,16 +3564,6 @@
         <attr name="__removed2" format="boolean" />
         <!-- Specifies whether the IME supports showing inline suggestions. -->
         <attr name="supportsInlineSuggestions" format="boolean" />
-        <!-- Specify one or more configuration changes that the IME will handle itself. If not
-             specified, the IME will be restarted if any of these configuration changes happen in
-              the system.  Otherwise, the IME will remain running and its
-             {@link android.inputmethodservice.InputMethodService#onConfigurationChanged}
-             method is called with the new configuration.
-             <p>Note that all of these configuration changes can impact the
-             resource values seen by the application, so you will generally need
-             to re-retrieve all resources (including view layouts, drawables, etc)
-             to correctly handle any configuration change.-->
-        <attr name="configChanges" />
     </declare-styleable>
 
     <!-- This is the subtype of InputMethod. Subtype can describe locales (for example, en_US and
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 0ae6a76..45e11ba 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1893,6 +1893,11 @@
             <!-- User data will remain unchanged during rollback. -->
             <enum name="retain" value="2" />
         </attr>
+
+        <!-- Applications can set this attribute to an xml resource within their app where they
+         specified the rules determining which files and directories can be copied from the device
+         as part of backup or transfer operations. -->
+        <attr name="dataExtractionRules" format="reference"/>
     </declare-styleable>
 
     <!-- An attribution is a logical part of an app and is identified by a tag.
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 59c260c..d79c01f 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -143,6 +143,10 @@
     <color name="notification_default_color_dark">@color/primary_text_default_material_light</color>
     <color name="notification_default_color_light">#a3202124</color>
 
+    <color name="notification_primary_text_color_current">@color/notification_primary_text_color_light</color>
+    <color name="notification_secondary_text_color_current">@color/notification_secondary_text_color_light</color>
+    <color name="notification_default_color_current">@color/notification_default_color_light</color>
+
     <color name="notification_default_color">#757575</color> <!-- Gray 600 -->
 
     <color name="notification_action_button_text_color">@color/notification_default_color</color>
diff --git a/core/res/res/values/colors_device_defaults.xml b/core/res/res/values/colors_device_defaults.xml
index 1020c14..9b56321 100644
--- a/core/res/res/values/colors_device_defaults.xml
+++ b/core/res/res/values/colors_device_defaults.xml
@@ -42,12 +42,7 @@
     <color name="background_floating_device_default_dark">@color/system_primary_900</color>
     <color name="background_floating_device_default_light">@color/system_primary_100</color>
 
-    <color name="text_color_primary_device_default_light">@color/system_primary_900</color>
-    <color name="text_color_primary_device_default_dark">@color/system_primary_50</color>
-    <color name="text_color_secondary_device_default_light">@color/system_primary_700</color>
-    <color name="text_color_secondary_device_default_dark">@color/system_primary_200</color>
-    <color name="text_color_tertiary_device_default_light">@color/system_primary_500</color>
-    <color name="text_color_tertiary_device_default_dark">@color/system_primary_400</color>
+    <!-- Please refer to text_color_[primary]_device_default_[light].xml for text colors-->
     <color name="foreground_device_default_light">@color/text_color_primary_device_default_light</color>
     <color name="foreground_device_default_dark">@color/text_color_primary_device_default_dark</color>
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9a917b7..a0cb3df 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -848,6 +848,15 @@
         <!-- y-intercept --> <item>1.000000000000000</item>
     </string-array>
 
+    <!-- Default strength, in percentage, of bright color reduction when activated. -->
+    <integer name="config_reduceBrightColorsStrengthDefault">0</integer>
+
+    <!-- Minimum strength, in percentage, supported by bright color reduction. -->
+    <integer name="config_reduceBrightColorsStrengthMin">0</integer>
+
+    <!-- Maximum strength, in percentage, supported by bright color reduction. -->
+    <integer name="config_reduceBrightColorsStrengthMax">100</integer>
+
     <!-- Boolean indicating whether display white balance is supported. -->
     <bool name="config_displayWhiteBalanceAvailable">false</bool>
 
@@ -1173,6 +1182,9 @@
     <!-- Default value for LED off time when the battery is low on charge in miliseconds -->
     <integer name="config_notificationsBatteryLedOff">2875</integer>
 
+    <!-- If true, only colorized CallStyle notifications will apply custom colors -->
+    <bool name="config_callNotificationActionColorsRequireColorized">true</bool>
+
     <!-- Number of notifications to keep in the notification service historical archive -->
     <integer name="config_notificationServiceArchiveSize">100</integer>
 
@@ -1780,7 +1792,7 @@
              * SDK level 28 makes the following algorithms mandatory : "cbc(aes)", "hmac(md5)",
                "hmac(sha1)", "hmac(sha256)", "hmac(sha384)", "hmac(sha512)", "rfc4106(gcm(aes))"
              * SDK level 31 makes the following algorithms mandatory : "rfc3686(ctr(aes))",
-               "xcbc(aes)", "rfc7539esp(chacha20,poly1305)"
+               "xcbc(aes)", "cmac(aes)", "rfc7539esp(chacha20,poly1305)"
      -->
     <string-array name="config_optionalIpSecAlgorithms" translatable="false">
         <!-- Add algorithm here -->
@@ -1950,6 +1962,8 @@
     <string name="config_systemShell" translatable="false">com.android.shell</string>
     <!-- The name of the package that will hold the system contacts role. -->
     <string name="config_systemContacts" translatable="false">com.android.contacts</string>
+    <!-- The name of the package that will hold the speech recognizer role by default. -->
+    <string name="config_systemSpeechRecognizer" translatable="false"></string>
 
     <!-- The name of the package that will be allowed to change its components' label/icon. -->
     <string name="config_overrideComponentUiPackage" translatable="false"></string>
@@ -3934,6 +3948,10 @@
          color supplied by the Notification.Builder if present. -->
     <bool name="config_tintNotificationActionButtons">true</bool>
 
+    <!-- Flag indicating that tinted items (actions, expander, etc) are to be tinted using the
+         theme color, rather than the notification color. -->
+    <bool name="config_tintNotificationsWithTheme">true</bool>
+
     <!-- Show area update info settings in CellBroadcastReceiver and information in SIM status in Settings app -->
     <bool name="config_showAreaUpdateInfoSettings">false</bool>
 
@@ -4648,15 +4666,6 @@
     <!-- WindowsManager JetPack display features -->
     <string name="config_display_features" translatable="false" />
 
-    <!-- Physical Display IDs of the display-devices that are swapped when a folding device folds.
-         This list is expected to contain two elements: the first is the display to use
-         when the device is folded, the second is the display to use when unfolded. If the array
-         is empty or the display IDs are not recognized, this feature is turned off and the value
-         ignored.
-         TODO: b/170470621 - remove once we can have multiple Internal displays in DMS as
-               well as a notification from DisplayStateManager. -->
-    <string-array name="config_internalFoldedPhysicalDisplayIds" translatable="false" />
-
     <!-- Aspect ratio of task level letterboxing. Values <= 1.0 will be ignored.
          Note: Activity min/max aspect ratio restrictions will still be respected by the
          activity-level letterboxing (size-compat mode). Therefore this override can control the
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 695a831..10aa7b3 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -224,7 +224,7 @@
     <dimen name="notification_content_margin_end">16dp</dimen>
 
     <!-- The margin on the end of the top-line content views (accommodates the expander) -->
-    <dimen name="notification_heading_margin_end">48dp</dimen>
+    <dimen name="notification_heading_margin_end">56dp</dimen>
 
     <!-- The margin for text at the end of the image view for media notifications -->
     <dimen name="notification_media_image_margin_end">72dp</dimen>
@@ -248,7 +248,7 @@
     <dimen name="call_notification_collapsible_indent">64dp</dimen>
 
     <!-- The size of icons for visual actions in the notification_material_action_list -->
-    <dimen name="notification_actions_icon_size">48dp</dimen>
+    <dimen name="notification_actions_icon_size">56dp</dimen>
 
     <!-- The size of icons for visual actions in the notification_material_action_list -->
     <dimen name="notification_actions_icon_drawable_size">20dp</dimen>
@@ -314,31 +314,27 @@
     <dimen name="notification_conversation_header_separating_margin">4dp</dimen>
 
     <!-- The absolute size of the notification expand icon. -->
-    <dimen name="notification_header_expand_icon_size">48dp</dimen>
+    <dimen name="notification_header_expand_icon_size">56dp</dimen>
 
-    <!-- The top padding for the notification expand button. -->
-    <dimen name="notification_expand_button_padding_top">1dp</dimen>
+    <!-- the height of the expand button pill -->
+    <dimen name="notification_expand_button_pill_height">24dp</dimen>
 
-    <!-- minimum vertical margin for the headerless notification content, when cap = 60dp -->
-    <dimen name="notification_headerless_margin_minimum">8dp</dimen>
+    <!-- Vertical margin for the headerless notification content, when content has 1 line -->
+    <!-- 16 * 2 (margins) + 24 (1 line) = 56 (notification) -->
+    <dimen name="notification_headerless_margin_oneline">16dp</dimen>
 
-    <!-- extra vertical margin for the headerless notification content, when cap = 60dp -->
-    <dimen name="notification_headerless_margin_extra">10dp</dimen>
-
-    <!-- minimum vertical margin for the headerless notification content, when cap = 48dp -->
-    <dimen name="notification_headerless_margin_constrained_minimum">14dp</dimen>
-
-    <!-- extra vertical margin for the headerless notification content, when cap = 48dp -->
-    <dimen name="notification_headerless_margin_constrained_extra">4dp</dimen>
+    <!-- Vertical margin for the headerless notification content, when content has 2 lines -->
+    <!-- 20 * 2 (margins) + 24 * 2 (2 lines) = 88 (notification) -->
+    <dimen name="notification_headerless_margin_twoline">20dp</dimen>
 
     <!-- The height of each of the 1 or 2 lines in the headerless notification template -->
-    <dimen name="notification_headerless_line_height">20sp</dimen>
+    <dimen name="notification_headerless_line_height">24dp</dimen>
 
     <!-- vertical margin for the headerless notification content -->
     <dimen name="notification_headerless_min_height">56dp</dimen>
 
     <!-- Height of a small notification in the status bar -->
-    <dimen name="notification_min_height">76dp</dimen>
+    <dimen name="notification_min_height">88dp</dimen>
 
     <!-- The width of the big icons in notifications. -->
     <dimen name="notification_large_icon_width">64dp</dimen>
@@ -694,6 +690,13 @@
     <!-- The default minimal size of a PiP task, in both dimensions. -->
     <dimen name="default_minimal_size_pip_resizable_task">108dp</dimen>
 
+    <!--
+      The overridable minimal size of a PiP task, in both dimensions.
+      Different from default_minimal_size_pip_resizable_task, this is to limit the dimension
+      when the pinned stack size is overridden by app via minWidth/minHeight.
+    -->
+    <dimen name="overridable_minimal_size_pip_resizable_task">48dp</dimen>
+
     <!-- Height of a task when in minimized mode from the top when launcher is resizable. -->
     <dimen name="task_height_of_minimized_mode">80dp</dimen>
 
@@ -738,11 +741,12 @@
     <!-- The maximum width of a image in a media notification. The images will be reduced to that width in case they are bigger.-->
     <dimen name="notification_media_image_max_width">280dp</dimen>
     <!-- The size of the right icon -->
-    <dimen name="notification_right_icon_size">52dp</dimen>
+    <dimen name="notification_right_icon_size">48dp</dimen>
     <!-- The top and bottom margin of the right icon in the normal notification states -->
-    <dimen name="notification_right_icon_headerless_margin">12dp</dimen>
+    <dimen name="notification_right_icon_headerless_margin">20dp</dimen>
     <!-- The top margin of the right icon in the "big" notification states -->
-    <dimen name="notification_right_icon_big_margin_top">16dp</dimen>
+    <!--  TODO(b/181048615): Move the large icon below the expander in big states  -->
+    <dimen name="notification_right_icon_big_margin_top">20dp</dimen>
     <!-- The size of the left icon -->
     <dimen name="notification_left_icon_size">@dimen/notification_icon_circle_size</dimen>
     <!-- The left padding of the left icon -->
@@ -773,13 +777,10 @@
     <dimen name="conversation_icon_circle_start">28dp</dimen>
     <!-- Start of the content in the conversation template -->
     <dimen name="conversation_content_start">80dp</dimen>
-    <!-- Size of the expand button in the conversation layout -->
-    <dimen name="conversation_expand_button_size">80dp</dimen>
-    <!-- Top margin of the expand button for conversations when expanded -->
-    <dimen name="conversation_expand_button_top_margin_expanded">18dp</dimen>
-    <!-- Side margin of the expand button for conversations.
-         width of expand asset (22) + 2 * this (13) == notification_header_expand_icon_size (48) -->
-    <dimen name="conversation_expand_button_side_margin">13dp</dimen>
+    <!-- Height of the expand button in the conversation layout -->
+    <dimen name="conversation_expand_button_height">80dp</dimen>
+    <!-- this is the margin between the Conversation image and the content -->
+    <dimen name="conversation_image_start_margin">12dp</dimen>
     <!-- Side margins of the conversation badge in relation to the conversation icon -->
     <dimen name="conversation_badge_side_margin">36dp</dimen>
     <!-- size of the notification badge when applied to the conversation icon -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 4732e5f..2004d0a 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3084,6 +3084,7 @@
     <public name="hand_minuteTintMode"/>
     <public name="hand_secondTint"/>
     <public name="hand_secondTintMode"/>
+    <public name="dataExtractionRules"/>
   </public-group>
 
   <public-group type="drawable" first-id="0x010800b5">
@@ -3165,6 +3166,8 @@
     <public name="config_customMediaKeyDispatcher" />
     <!-- @hide @SystemApi -->
     <public name="config_customMediaSessionPolicyProvider" />
+    <!-- @hide @SystemApi -->
+    <public name="config_systemSpeechRecognizer" />
   </public-group>
 
   <public-group type="id" first-id="0x01020055">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 760313a..71ba44b 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1644,7 +1644,7 @@
     <!-- Message shown during acqusition when the user's face is turned too far left or right [CHAR LIMIT=50] -->
     <string name="face_acquired_pan_too_extreme">Turn your head a little less.</string>
     <!-- Message shown during acqusition when the user's face is tilted too high or too low [CHAR LIMIT=50] -->
-    <string name="face_acquired_tilt_too_extreme">Turn your head a little less.</string>
+    <string name="face_acquired_tilt_too_extreme">Tilt your head a little less.</string>
     <!-- Message shown during acquisiton when the user's face is tilted too far left or right [CHAR LIMIT=50] -->
     <string name="face_acquired_roll_too_extreme">Turn your head a little less.</string>
     <!-- Message shown during acquisition when the user's face is obscured [CHAR LIMIT=50] -->
@@ -5011,6 +5011,9 @@
     <!-- Content description of the alerting icon in the notification. [CHAR_LIMIT=NONE] -->
     <string name="notification_alerted_content_description">Alerted</string>
 
+    <!-- Default content description of the verification icon in the call notification. [CHAR_LIMIT=NONE] -->
+    <string name="notification_verified_content_description">Verified</string>
+
     <!-- Content description of the expand button icon in the notification when collaped.-->
     <string name="expand_button_content_description_collapsed">Expand</string>
 
@@ -5849,4 +5852,8 @@
     <!--- Label for notification channel for all sensor privacy related notifications. [CHAR LIMIT=NONE] -->
     <string name="sensor_privacy_notification_channel_label">Sensor Privacy</string>
 
+    <!-- Content description for the icon on the splash screen. [CHAR LIMIT=50] -->
+    <string name="splash_screen_view_icon_description">Application icon</string>
+    <!-- Content description for the branding image on the splash screen. [CHAR LIMIT=50] -->
+    <string name="splash_screen_view_branding_description">Application branding image</string>
 </resources>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 158289a..3c4a5d4 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -466,18 +466,20 @@
     </style>
 
     <style name="TextAppearance.Material.Notification">
-        <item name="textColor">@color/notification_secondary_text_color_light</item>
+        <item name="textColor">@color/notification_secondary_text_color_current</item>
         <item name="textSize">@dimen/notification_text_size</item>
     </style>
 
     <style name="TextAppearance.Material.Notification.Reply" />
 
     <style name="TextAppearance.Material.Notification.Title">
+        <item name="textColor">@color/notification_primary_text_color_current</item>
         <item name="fontFamily">sans-serif-medium</item>
         <item name="textSize">@dimen/notification_title_text_size</item>
     </style>
 
     <style name="TextAppearance.Material.Notification.BigTitle">
+        <item name="textColor">@color/notification_primary_text_color_current</item>
         <item name="fontFamily">sans-serif-medium</item>
         <item name="textSize">@dimen/notification_big_title_text_size</item>
     </style>
@@ -492,9 +494,8 @@
 
     <style name="TextAppearance.Material.Notification.Time" parent="TextAppearance.Material.Notification.Info" />
 
-    <style name="TextAppearance.Material.Notification.Emphasis">
-        <item name="textColor">#66000000</item>
-    </style>
+    <!-- unused; keep identical to parent -->
+    <style name="TextAppearance.Material.Notification.Emphasis"/>
 
     <style name="TextAppearance.Material.Notification.Conversation.AppName" parent="TextAppearance.Material.Notification.Title">
         <item name="android:textSize">16sp</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b5af524..e380f40 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1893,6 +1893,7 @@
   <java-symbol type="bool" name="config_notificationHeaderClickableForExpand" />
   <java-symbol type="bool" name="config_enableNightMode" />
   <java-symbol type="bool" name="config_tintNotificationActionButtons" />
+  <java-symbol type="bool" name="config_tintNotificationsWithTheme" />
   <java-symbol type="bool" name="config_dozeAfterScreenOffByDefault" />
   <java-symbol type="bool" name="config_enableActivityRecognitionHardwareOverlay" />
   <java-symbol type="bool" name="config_enableFusedLocationOverlay" />
@@ -1948,6 +1949,7 @@
   <java-symbol type="fraction" name="config_dimBehindFadeDuration" />
   <java-symbol type="dimen" name="default_minimal_size_resizable_task" />
   <java-symbol type="dimen" name="default_minimal_size_pip_resizable_task" />
+  <java-symbol type="dimen" name="overridable_minimal_size_pip_resizable_task" />
   <java-symbol type="dimen" name="task_height_of_minimized_mode" />
   <java-symbol type="fraction" name="config_screenAutoBrightnessDozeScaleFactor" />
   <java-symbol type="bool" name="config_allowPriorityVibrationsInLowPowerMode" />
@@ -2286,6 +2288,7 @@
   <java-symbol type="string" name="config_wifi_tether_enable" />
   <java-symbol type="bool" name="config_intrusiveNotificationLed" />
   <java-symbol type="bool" name="config_notificationBadging" />
+  <java-symbol type="bool" name="config_callNotificationActionColorsRequireColorized" />
   <java-symbol type="dimen" name="preference_fragment_padding_bottom" />
   <java-symbol type="dimen" name="preference_fragment_padding_side" />
   <java-symbol type="drawable" name="expander_ic_maximized" />
@@ -2891,11 +2894,12 @@
   <java-symbol type="id" name="header_text" />
   <java-symbol type="id" name="header_text_secondary" />
   <java-symbol type="id" name="expand_button" />
+  <java-symbol type="id" name="expand_button_pill" />
+  <java-symbol type="id" name="expand_button_number" />
+  <java-symbol type="id" name="expand_button_icon" />
   <java-symbol type="id" name="alternate_expand_target" />
   <java-symbol type="id" name="notification_header" />
   <java-symbol type="id" name="notification_top_line" />
-  <java-symbol type="id" name="notification_headerless_margin_extra_top" />
-  <java-symbol type="id" name="notification_headerless_margin_extra_bottom" />
   <java-symbol type="id" name="time_divider" />
   <java-symbol type="id" name="header_text_divider" />
   <java-symbol type="id" name="header_text_secondary_divider" />
@@ -2913,12 +2917,11 @@
   <java-symbol type="dimen" name="notification_header_background_height" />
   <java-symbol type="dimen" name="notification_header_touchable_height" />
   <java-symbol type="dimen" name="notification_header_expand_icon_size" />
-  <java-symbol type="dimen" name="notification_expand_button_padding_top" />
   <java-symbol type="dimen" name="notification_header_icon_size" />
   <java-symbol type="dimen" name="notification_header_app_name_margin_start" />
   <java-symbol type="dimen" name="notification_header_separating_margin" />
-  <java-symbol type="dimen" name="notification_headerless_margin_constrained_minimum" />
-  <java-symbol type="dimen" name="notification_headerless_margin_constrained_extra" />
+  <java-symbol type="dimen" name="notification_headerless_margin_oneline" />
+  <java-symbol type="dimen" name="notification_headerless_margin_twoline" />
   <java-symbol type="string" name="default_notification_channel_label" />
   <java-symbol type="string" name="importance_from_user" />
   <java-symbol type="string" name="importance_from_person" />
@@ -3111,8 +3114,10 @@
   <java-symbol type="dimen" name="call_notification_collapsible_indent"/>
   <java-symbol type="drawable" name="ic_call_answer" />
   <java-symbol type="drawable" name="ic_call_decline" />
+  <java-symbol type="id" name="verification_divider" />
   <java-symbol type="id" name="verification_icon" />
   <java-symbol type="id" name="verification_text" />
+  <java-symbol type="string" name="notification_verified_content_description" />
 
   <!-- Notification handler / dashboard package -->
   <java-symbol type="string" name="config_notificationHandlerPackage" />
@@ -3223,6 +3228,9 @@
   <java-symbol type="bool" name="config_reduceBrightColorsAvailable" />
   <java-symbol type="array" name="config_reduceBrightColorsCoefficients" />
   <java-symbol type="array" name="config_reduceBrightColorsCoefficientsNonlinear" />
+  <java-symbol type="integer" name="config_reduceBrightColorsStrengthDefault" />
+  <java-symbol type="integer" name="config_reduceBrightColorsStrengthMin" />
+  <java-symbol type="integer" name="config_reduceBrightColorsStrengthMax" />
   <java-symbol type="array" name="config_availableColorModes" />
   <java-symbol type="array" name="config_mappedColorModes" />
   <java-symbol type="string" name="config_vendorColorModesRestoreHint" />
@@ -4028,7 +4036,6 @@
   <java-symbol type="id" name="message_icon_container" />
   <java-symbol type="id" name="conversation_image_message_container" />
   <java-symbol type="id" name="conversation_icon_container" />
-  <java-symbol type="dimen" name="conversation_expand_button_top_margin_expanded" />
   <java-symbol type="dimen" name="messaging_group_singleline_sender_padding_end" />
   <java-symbol type="dimen" name="conversation_badge_side_margin" />
   <java-symbol type="dimen" name="conversation_avatar_size" />
@@ -4049,7 +4056,6 @@
   <java-symbol type="dimen" name="button_padding_horizontal_material" />
   <java-symbol type="dimen" name="button_inset_horizontal_material" />
   <java-symbol type="layout" name="conversation_face_pile_layout" />
-  <java-symbol type="id" name="conversation_unread_count" />
   <java-symbol type="string" name="unread_convo_overflow" />
   <java-symbol type="style" name="TextAppearance.DeviceDefault.Notification.Conversation.AppName" />
   <java-symbol type="drawable" name="conversation_badge_background" />
@@ -4156,7 +4162,6 @@
   <java-symbol type="dimen" name="default_background_blur_radius" />
   <java-symbol type="array" name="config_keep_warming_services" />
   <java-symbol type="string" name="config_display_features" />
-  <java-symbol type="array" name="config_internalFoldedPhysicalDisplayIds" />
 
   <java-symbol type="dimen" name="controls_thumbnail_image_max_height" />
   <java-symbol type="dimen" name="controls_thumbnail_image_max_width" />
@@ -4203,4 +4208,6 @@
   <java-symbol type="bool" name="config_telephony5gNonStandalone" />
 
   <java-symbol type="bool" name="config_voice_data_sms_auto_fallback" />
+
+  <java-symbol type="bool" name="config_enableOneHandedKeyguard" />
 </resources>
diff --git a/core/tests/GameManagerTests/Android.bp b/core/tests/GameManagerTests/Android.bp
index e178776..2789e9f 100644
--- a/core/tests/GameManagerTests/Android.bp
+++ b/core/tests/GameManagerTests/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+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_test {
     name: "FrameworksCoreGameManagerTests",
     // Include all test java files
diff --git a/core/tests/batterystatstests/BatteryStatsLoadTests/Android.bp b/core/tests/batterystatstests/BatteryStatsLoadTests/Android.bp
index ade97b8..1c0ea83 100644
--- a/core/tests/batterystatstests/BatteryStatsLoadTests/Android.bp
+++ b/core/tests/batterystatstests/BatteryStatsLoadTests/Android.bp
@@ -1,3 +1,12 @@
+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_test {
     name: "BatteryStatsLoadTests",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/Android.bp b/core/tests/batterystatstests/BatteryStatsViewer/Android.bp
index 1e0498b..c2e7d81 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/Android.bp
+++ b/core/tests/batterystatstests/BatteryStatsViewer/Android.bp
@@ -1,3 +1,12 @@
+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_test {
     name: "BatteryStatsViewer",
     srcs: ["src/**/*.java"],
diff --git a/core/tests/benchmarks/src/android/os/ParcelableBenchmark.java b/core/tests/benchmarks/src/android/os/ParcelableBenchmark.java
new file mode 100644
index 0000000..1cf4302
--- /dev/null
+++ b/core/tests/benchmarks/src/android/os/ParcelableBenchmark.java
@@ -0,0 +1,133 @@
+/*
+ * 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.os;
+
+import android.annotation.SuppressLint;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.util.MergedConfiguration;
+import android.view.InsetsSource;
+import android.view.InsetsState;
+
+import com.google.caliper.AfterExperiment;
+import com.google.caliper.BeforeExperiment;
+
+/**
+ * Benchmark of read/write large Parcelable class. This also shows the performance of different
+ * implementations for nested Parcelable class:
+ * <ul>
+ *   <li>Well-written read/writeFromParcel (direct access)</li>
+ *   <li>read/writeTypedObject (object creation + addition int to indicate nullity)</li>
+ *   <li>read/writeParcelable (object creation + addition type String)</li>
+ * </ul>
+ */
+public class ParcelableBenchmark {
+    private Parcel mParcel;
+
+    @BeforeExperiment
+    protected void setUp() {
+        mParcel = Parcel.obtain();
+    }
+
+    @AfterExperiment
+    protected void tearDown() {
+        mParcel.recycle();
+        mParcel = null;
+    }
+
+    public void timeReadWriteMergedConfiguration(int reps) {
+        final MergedConfiguration mergedConfiguration = new MergedConfiguration();
+        for (int i = 0; i < reps; i++) {
+            mergedConfiguration.writeToParcel(mParcel, 0);
+            mParcel.setDataPosition(0);
+            mergedConfiguration.readFromParcel(mParcel);
+        }
+    }
+
+    public void timeReadWriteInsetsState(int reps) {
+        final InsetsState insetsState = new InsetsState();
+        for (int i = 0; i < InsetsState.SIZE; i++) {
+            insetsState.addSource(new InsetsSource(i));
+        }
+        for (int i = 0; i < reps; i++) {
+            insetsState.writeToParcel(mParcel, 0);
+            mParcel.setDataPosition(0);
+            insetsState.readFromParcel(mParcel);
+        }
+    }
+
+    public void timeReadWritePointArray(int reps) {
+        final PointArray pointArray = new PointArray();
+        for (int i = 0; i < reps; i++) {
+            pointArray.writeToParcel(mParcel, 0);
+            mParcel.setDataPosition(0);
+            pointArray.readFromParcel(mParcel);
+        }
+    }
+
+    public void timeReadWritePointArrayFast(int reps) {
+        final PointArrayFast pointArray = new PointArrayFast();
+        for (int i = 0; i < reps; i++) {
+            pointArray.writeToParcel(mParcel, 0);
+            mParcel.setDataPosition(0);
+            pointArray.readFromParcel(mParcel);
+        }
+    }
+
+    @SuppressLint("ParcelCreator")
+    private static class PointArray implements Parcelable {
+        Rect mBounds = new Rect();
+        Point[] mPoints = new Point[10];
+        {
+            for (int i = 0; i < mPoints.length; i++) {
+                mPoints[i] = new Point();
+            }
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeParcelable(mBounds, flags);
+            dest.writeParcelableArray(mPoints, flags);
+        }
+
+        void readFromParcel(Parcel in) {
+            mBounds = in.readParcelable(Rect.class.getClassLoader());
+            mPoints = in.readParcelableArray(Point.class.getClassLoader(), Point.class);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+    }
+
+    @SuppressLint("ParcelCreator")
+    private static class PointArrayFast extends PointArray {
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            mBounds.writeToParcel(dest, flags);
+            dest.writeTypedArray(mPoints, flags);
+        }
+
+        @Override
+        void readFromParcel(Parcel in) {
+            mBounds.readFromParcel(in);
+            in.readTypedArray(mPoints, Point.CREATOR);
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/app/backup/BackupAgentTest.java b/core/tests/coretests/src/android/app/backup/BackupAgentTest.java
index ea903f2..37cf470 100644
--- a/core/tests/coretests/src/android/app/backup/BackupAgentTest.java
+++ b/core/tests/coretests/src/android/app/backup/BackupAgentTest.java
@@ -57,14 +57,6 @@
     }
 
     @Test
-    public void testGetIncludeExcludeRules_isMigration_returnsEmptyRules()  throws Exception {
-        mBackupAgent = getAgentForOperationType(OperationType.MIGRATION);
-
-        IncludeExcludeRules rules = mBackupAgent.getIncludeExcludeRules(mBackupScheme);
-        assertThat(rules).isEqualTo(IncludeExcludeRules.emptyRules());
-    }
-
-    @Test
     public void testGetIncludeExcludeRules_isNotMigration_returnsRules() throws Exception {
         PathWithRequiredFlags path = new PathWithRequiredFlags("path", /* requiredFlags */ 0);
         Map<String, Set<PathWithRequiredFlags>> includePaths = Collections.singletonMap("test",
diff --git a/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java b/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java
index 1573c19..7cb6804 100644
--- a/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java
+++ b/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java
@@ -37,6 +37,7 @@
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Parcel;
+import android.os.UserHandle;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
@@ -124,13 +125,13 @@
     }
 
     @Test
-    public void testUid() {
+    public void testUserHandle() {
         PeopleSpaceTile tile = new PeopleSpaceTile
                 .Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps)
-                .setUid(42)
+                .setUserHandle(new UserHandle(0))
                 .build();
 
-        assertThat(tile.getUid()).isEqualTo(42);
+        assertThat(tile.getUserHandle()).isEqualTo(new UserHandle(0));
     }
 
     @Test
@@ -227,7 +228,7 @@
                 .setUserName("name")
                 .setUserIcon(mIcon)
                 .setContactUri(Uri.parse("contact"))
-                .setUid(42)
+                .setUserHandle(new UserHandle(1))
                 .setPackageName("package.name")
                 .setLastInteractionTimestamp(7L)
                 .setIsImportantConversation(true)
@@ -246,7 +247,7 @@
         assertThat(readTile.getUserName()).isEqualTo(tile.getUserName());
         assertThat(readTile.getUserIcon().toString()).isEqualTo(tile.getUserIcon().toString());
         assertThat(readTile.getContactUri()).isEqualTo(tile.getContactUri());
-        assertThat(readTile.getUid()).isEqualTo(tile.getUid());
+        assertThat(readTile.getUserHandle()).isEqualTo(tile.getUserHandle());
         assertThat(readTile.getPackageName()).isEqualTo(tile.getPackageName());
         assertThat(readTile.getLastInteractionTimestamp()).isEqualTo(
                 tile.getLastInteractionTimestamp());
diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
index 50b52eb..6c8b941 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -148,13 +148,15 @@
         PersistableBundle persistableBundle = new PersistableBundle();
         persistableBundle.putInt("k", 4);
         IBinder assistToken = new Binder();
+        IBinder shareableActivityToken = new Binder();
 
         Supplier<LaunchActivityItem> itemSupplier = () -> new LaunchActivityItemBuilder()
                 .setIntent(intent).setIdent(ident).setInfo(activityInfo).setCurConfig(config())
                 .setOverrideConfig(overrideConfig).setCompatInfo(compat).setReferrer(referrer)
                 .setProcState(procState).setState(bundle).setPersistentState(persistableBundle)
                 .setPendingResults(resultInfoList()).setPendingNewIntents(referrerIntentList())
-                .setIsForward(true).setAssistToken(assistToken).build();
+                .setIsForward(true).setAssistToken(assistToken)
+                .setShareableActivityToken(shareableActivityToken).build();
 
         LaunchActivityItem emptyItem = new LaunchActivityItemBuilder().build();
         LaunchActivityItem item = itemSupplier.get();
diff --git a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
index 02e75dd..1a06789e 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
@@ -109,6 +109,7 @@
         private boolean mIsForward;
         private ProfilerInfo mProfilerInfo;
         private IBinder mAssistToken;
+        private IBinder mShareableActivityToken;
         private FixedRotationAdjustments mFixedRotationAdjustments;
 
         LaunchActivityItemBuilder setIntent(Intent intent) {
@@ -196,6 +197,11 @@
             return this;
         }
 
+        LaunchActivityItemBuilder setShareableActivityToken(IBinder shareableActivityToken) {
+            mShareableActivityToken = shareableActivityToken;
+            return this;
+        }
+
         LaunchActivityItemBuilder setFixedRotationAdjustments(FixedRotationAdjustments fra) {
             mFixedRotationAdjustments = fra;
             return this;
@@ -206,7 +212,8 @@
                     mCurConfig, mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor,
                     mProcState, mState, mPersistentState, mPendingResults, mPendingNewIntents,
                     mActivityOptions, mIsForward, mProfilerInfo, mAssistToken,
-                    null /* activityClientController */, mFixedRotationAdjustments);
+                    null /* activityClientController */, mFixedRotationAdjustments,
+                    mShareableActivityToken);
         }
     }
 }
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index f6d985b..6f3d7ae 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -207,6 +207,7 @@
                 .setPendingResults(resultInfoList()).setActivityOptions(ActivityOptions.makeBasic())
                 .setPendingNewIntents(referrerIntentList()).setIsForward(true)
                 .setAssistToken(new Binder()).setFixedRotationAdjustments(fixedRotationAdjustments)
+                .setShareableActivityToken(new Binder())
                 .build();
 
         writeAndPrepareForReading(item);
diff --git a/core/tests/coretests/src/android/app/usage/OWNERS b/core/tests/coretests/src/android/app/usage/OWNERS
new file mode 100644
index 0000000..1271fa79
--- /dev/null
+++ b/core/tests/coretests/src/android/app/usage/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 532296
+include /services/usage/OWNERS
diff --git a/core/tests/coretests/src/android/content/pm/AppSearchShortcutInfoTest.java b/core/tests/coretests/src/android/content/pm/AppSearchShortcutInfoTest.java
index da92e69..ffe93bc 100644
--- a/core/tests/coretests/src/android/content/pm/AppSearchShortcutInfoTest.java
+++ b/core/tests/coretests/src/android/content/pm/AppSearchShortcutInfoTest.java
@@ -47,15 +47,16 @@
         final Intent shortcutIntent = new Intent(Intent.ACTION_VIEW);
         final ShortcutInfo shortcut = new AppSearchShortcutInfo.Builder(id)
                 .setActivity(activity)
-                .setText(id)
+                .setLongLabel(id)
                 .setIconResName(shortcutIconResName)
                 .setIntent(shortcutIntent)
                 .setPerson(person)
                 .setCategories(categorySet)
                 .setFlags(ShortcutInfo.FLAG_LONG_LIVED)
                 .build()
-                .toShortcutInfo();
+                .toShortcutInfo(0);
 
+        assertThat(shortcut.getUserId()).isEqualTo(0);
         assertThat(shortcut.getId()).isEqualTo(id);
         assertThat(shortcut.getShortLabel()).isEqualTo(id);
         assertThat(shortcut.getIconResName()).isEqualTo(shortcutIconResName);
diff --git a/core/tests/coretests/src/android/inputmethodservice/InputMethodServiceTest.java b/core/tests/coretests/src/android/inputmethodservice/InputMethodServiceTest.java
deleted file mode 100644
index 8906149..0000000
--- a/core/tests/coretests/src/android/inputmethodservice/InputMethodServiceTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.inputmethodservice;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-
-import static junit.framework.Assert.assertFalse;
-
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.content.pm.ActivityInfo;
-import android.content.res.Configuration;
-import android.os.Build;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.rule.ServiceTestRule;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.concurrent.TimeoutException;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class InputMethodServiceTest {
-    private InputMethodService mService;
-    private Context mContext;
-    @Rule
-    public final ServiceTestRule serviceRule = new ServiceTestRule();
-
-    @Before
-    public void setUp() throws TimeoutException {
-        mContext = getInstrumentation().getContext();
-        mService = new InputMethodService();
-    }
-
-    @Test
-    public void testShouldImeRestartForConfig() throws Exception {
-        // Make sure we preserve Pre-S behavior i.e. Service restarts.
-        mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.R;
-        Configuration config = mContext.getResources().getConfiguration();
-        mService.setLastKnownConfig(config);
-        assertTrue("IME should restart for Pre-S",
-                mService.shouldImeRestartForConfig(config));
-
-        // IME shouldn't restart on targetSdk S+ (with no config changes).
-        mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.S;
-        assertFalse("IME shouldn't restart for S+",
-                mService.shouldImeRestartForConfig(config));
-
-        // Screen density changed but IME doesn't handle congfigChanges
-        config.densityDpi = 99;
-        assertTrue("IME should restart for unhandled configChanges",
-                mService.shouldImeRestartForConfig(config));
-
-        // opt-in IME to handle config changes.
-        mService.setHandledConfigChanges(ActivityInfo.CONFIG_DENSITY);
-        assertFalse("IME shouldn't restart for S+ since it handles configChanges",
-                mService.shouldImeRestartForConfig(config));
-    }
-}
diff --git a/core/tests/coretests/src/android/util/RotationUtilsTest.java b/core/tests/coretests/src/android/util/RotationUtilsTest.java
new file mode 100644
index 0000000..5dbe03e
--- /dev/null
+++ b/core/tests/coretests/src/android/util/RotationUtilsTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.util;
+
+import static android.util.RotationUtils.rotateBounds;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import static org.junit.Assert.assertEquals;
+
+import android.graphics.Rect;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link RotationUtils}.
+ *
+ * Build/Install/Run:
+ *  atest FrameworksCoreTests:RotationUtilsTest
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RotationUtilsTest {
+
+    @Test
+    public void testRotateBounds() {
+        Rect testParent = new Rect(0, 0, 1000, 600);
+        Rect testInner = new Rect(40, 20, 120, 80);
+
+        Rect testResult = new Rect(testInner);
+        rotateBounds(testResult, testParent, ROTATION_90);
+        assertEquals(new Rect(20, 880, 80, 960), testResult);
+
+        testResult.set(testInner);
+        rotateBounds(testResult, testParent, ROTATION_180);
+        assertEquals(new Rect(880, 520, 960, 580), testResult);
+
+        testResult.set(testInner);
+        rotateBounds(testResult, testParent, ROTATION_270);
+        assertEquals(new Rect(520, 40, 580, 120), testResult);
+    }
+}
diff --git a/core/tests/coretests/src/android/view/BlurAggregatorTest.java b/core/tests/coretests/src/android/view/BlurAggregatorTest.java
new file mode 100644
index 0000000..b01f275
--- /dev/null
+++ b/core/tests/coretests/src/android/view/BlurAggregatorTest.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertNotNull;
+import static junit.framework.TestCase.assertNull;
+import static junit.framework.TestCase.assertTrue;
+
+import android.content.Context;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.internal.graphics.drawable.BackgroundBlurDrawable;
+import com.android.internal.graphics.drawable.BackgroundBlurDrawable.Aggregator;
+import com.android.internal.graphics.drawable.BackgroundBlurDrawable.BlurRegion;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class BlurAggregatorTest {
+    private static final int TEST_BLUR_RADIUS = 30;
+    private static final int TEST_FRAME_NUMBER = 1;
+
+    private Context mContext;
+
+    private Aggregator mAggregator;
+    private BackgroundBlurDrawable mDrawable;
+
+    private ViewRootImpl mViewRoot;
+
+    @Before
+    public void setUp() {
+        mContext = getInstrumentation().getTargetContext();
+        getInstrumentation().runOnMainSync(() -> {
+            mViewRoot = new ViewRootImpl(mContext, mContext.getDisplayNoVerify());
+        });
+        mAggregator = new Aggregator(mViewRoot);
+        mDrawable = createTestBackgroundBlurDrawable();
+    }
+
+    private BackgroundBlurDrawable createTestBackgroundBlurDrawable() {
+        final BackgroundBlurDrawable drawable = mAggregator.createBackgroundBlurDrawable(mContext);
+        drawable.setBlurRadius(TEST_BLUR_RADIUS);
+        final boolean hasUpdates = mAggregator.hasUpdates();
+        final BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+        mAggregator.getBlurRegionsToDispatchToSf(TEST_FRAME_NUMBER, blurRegions, hasUpdates);
+        return drawable;
+    }
+
+    @Test
+    public void testBlurRadiusUpdatePropagatesToRenderThreadIfNeeded() {
+        mDrawable.setBlurRadius(TEST_BLUR_RADIUS);
+        assertFalse(mAggregator.hasUpdates());
+
+        mDrawable.setBlurRadius(0);
+        assertTrue(mAggregator.hasUpdates());
+        BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+        assertEquals(0, blurRegions.length);
+        assertFalse(mAggregator.hasUpdates());
+
+        mDrawable.setBlurRadius(TEST_BLUR_RADIUS);
+        assertTrue(mAggregator.hasUpdates());
+        blurRegions = mAggregator.getBlurRegionsCopyForRT();
+        assertEquals(1, blurRegions.length);
+        assertEquals(TEST_BLUR_RADIUS, blurRegions[0].blurRadius);
+        assertFalse(mAggregator.hasUpdates());
+
+    }
+
+    @Test
+    public void testAlphaUpdatePropagatesToRenderThreadIfNeeded() {
+        mDrawable.setAlpha(20);
+        assertTrue(mAggregator.hasUpdates());
+        BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+        assertEquals(1, blurRegions.length);
+        assertEquals(20 / 255f, blurRegions[0].alpha);
+        assertFalse(mAggregator.hasUpdates());
+
+        mDrawable.setAlpha(20);
+        assertFalse(mAggregator.hasUpdates());
+
+        mDrawable.setAlpha(0);
+        assertTrue(mAggregator.hasUpdates());
+        blurRegions = mAggregator.getBlurRegionsCopyForRT();
+        assertEquals(0, blurRegions.length);
+        assertFalse(mAggregator.hasUpdates());
+    }
+
+    @Test
+    public void testCornerRadiusUpdatePropagatesToRenderThreadIfNeeded() {
+        mDrawable.setCornerRadius(1f, 2f, 3f, 4f);
+        assertTrue(mAggregator.hasUpdates());
+        final BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+        assertEquals(1, blurRegions.length);
+        assertEquals(1f, blurRegions[0].cornerRadiusTL);
+        assertEquals(2f, blurRegions[0].cornerRadiusTR);
+        assertEquals(3f, blurRegions[0].cornerRadiusBL);
+        assertEquals(4f, blurRegions[0].cornerRadiusBR);
+        assertFalse(mAggregator.hasUpdates());
+    }
+
+    @Test
+    public void testVisibleUpdatePropagatesToRenderThreadIfNeeded() {
+        mDrawable.setVisible(false, /* restart= */false);
+        assertTrue(mAggregator.hasUpdates());
+        BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+        assertEquals(0, blurRegions.length);
+        assertFalse(mAggregator.hasUpdates());
+
+        mDrawable.setVisible(true, /* restart= */ false);
+        assertTrue(mAggregator.hasUpdates());
+        blurRegions = mAggregator.getBlurRegionsCopyForRT();
+        assertEquals(1, blurRegions.length);
+        assertEquals(TEST_BLUR_RADIUS, blurRegions[0].blurRadius);
+        assertFalse(mAggregator.hasUpdates());
+    }
+
+    @Test
+    public void testBlurRegionCopyForRtIsSameIfNoUiUpdates() {
+        mDrawable.setBlurRadius(30);
+        BlurRegion[] blurRegions1 = mAggregator.getBlurRegionsCopyForRT();
+        assertEquals(1, blurRegions1.length);
+        assertEquals(30, blurRegions1[0].blurRadius);
+
+        BlurRegion[] blurRegions2 = mAggregator.getBlurRegionsCopyForRT();
+        assertEquals(blurRegions1, blurRegions2);
+    }
+
+    @Test
+    public void testPositionUpdateAppearsInBlurRegion() {
+        BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+        assertEquals(1, blurRegions.length);
+
+        mDrawable.mPositionUpdateListener.positionChanged(TEST_FRAME_NUMBER, 1, 2, 3, 4);
+        mAggregator.getBlurRegionsToDispatchToSf(TEST_FRAME_NUMBER, blurRegions,
+                mAggregator.hasUpdates());
+        assertEquals(1, blurRegions[0].rect.left);
+        assertEquals(2, blurRegions[0].rect.top);
+        assertEquals(3, blurRegions[0].rect.right);
+        assertEquals(4, blurRegions[0].rect.bottom);
+    }
+
+    @Test
+    public void testNoBlurRegionsDispatchedWhenNoUpdates() {
+        final boolean hasUpdates = mAggregator.hasUpdates();
+        assertFalse(hasUpdates);
+        final BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+        assertEquals(1, blurRegions.length);
+
+        float[][] blurRegionsForSf = mAggregator.getBlurRegionsToDispatchToSf(
+                TEST_FRAME_NUMBER, blurRegions, hasUpdates);
+        assertNull(blurRegionsForSf);
+    }
+
+    @Test
+    public void testBlurRegionDispatchedIfOnlyDrawableUpdated() {
+        mDrawable.setBlurRadius(50);
+        final boolean hasUpdates = mAggregator.hasUpdates();
+        assertTrue(hasUpdates);
+        final BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+        assertEquals(1, blurRegions.length);
+
+        float[][] blurRegionsForSf = mAggregator.getBlurRegionsToDispatchToSf(
+                TEST_FRAME_NUMBER, blurRegions, hasUpdates);
+        assertNotNull(blurRegionsForSf);
+        assertEquals(1, blurRegionsForSf.length);
+        assertEquals(50f, blurRegionsForSf[0][0]);
+    }
+
+    @Test
+    public void testBlurRegionDispatchedIfOnlyPositionUpdated() {
+        final boolean hasUpdates = mAggregator.hasUpdates();
+        assertFalse(hasUpdates);
+        final BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+        assertEquals(1, blurRegions.length);
+
+        mDrawable.mPositionUpdateListener.positionChanged(TEST_FRAME_NUMBER, 1, 2, 3, 4);
+        float[][] blurRegionsForSf = mAggregator.getBlurRegionsToDispatchToSf(
+                TEST_FRAME_NUMBER, blurRegions, hasUpdates);
+        assertNotNull(blurRegionsForSf);
+        assertEquals(1, blurRegionsForSf.length);
+        assertEquals((float) TEST_BLUR_RADIUS, blurRegionsForSf[0][0]);
+        assertEquals(1f, blurRegionsForSf[0][2]);
+        assertEquals(2f, blurRegionsForSf[0][3]);
+        assertEquals(3f, blurRegionsForSf[0][4]);
+        assertEquals(4f, blurRegionsForSf[0][5]);
+    }
+
+    @Test
+    public void testPositionUpdateIsAppliedInNextFrameIfMissed() {
+        final boolean hasUpdates = mAggregator.hasUpdates();
+        assertFalse(hasUpdates);
+        final BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+        assertEquals(1, blurRegions.length);
+
+        mDrawable.mPositionUpdateListener.positionChanged(TEST_FRAME_NUMBER, 1, 2, 3, 4);
+        float[][] blurRegionsForSf = mAggregator.getBlurRegionsToDispatchToSf(
+                TEST_FRAME_NUMBER + 1, blurRegions, hasUpdates);
+        assertNotNull(blurRegionsForSf);
+        assertEquals(1, blurRegionsForSf.length);
+        assertEquals((float) TEST_BLUR_RADIUS, blurRegionsForSf[0][0]);
+        assertEquals(1f, blurRegionsForSf[0][2]);
+        assertEquals(2f, blurRegionsForSf[0][3]);
+        assertEquals(3f, blurRegionsForSf[0][4]);
+        assertEquals(4f, blurRegionsForSf[0][5]);
+    }
+
+    @Test
+    public void testMultipleDrawablesDispatchedToSfIfOneIsUpdated() {
+        final BackgroundBlurDrawable drawable2 = createTestBackgroundBlurDrawable();
+        drawable2.setBlurRadius(50);
+        final boolean hasUpdates = mAggregator.hasUpdates();
+        assertTrue(hasUpdates);
+        final BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+        assertEquals(2, blurRegions.length);
+
+        // Check that an update in one of the drawables triggers a dispatch of all blur regions
+        float[][] blurRegionsForSf = mAggregator.getBlurRegionsToDispatchToSf(
+                TEST_FRAME_NUMBER, blurRegions, hasUpdates);
+        assertNotNull(blurRegionsForSf);
+        assertEquals(2, blurRegionsForSf.length);
+
+        // Check that the Aggregator deleted all position updates for frame TEST_FRAME_NUMBER
+        blurRegionsForSf = mAggregator.getBlurRegionsToDispatchToSf(
+                TEST_FRAME_NUMBER, blurRegions, /* hasUiUpdates= */ false);
+        assertNull(blurRegionsForSf);
+
+        // Check that a position update triggers a dispatch of all blur regions
+        drawable2.mPositionUpdateListener.positionChanged(TEST_FRAME_NUMBER, 1, 2, 3, 4);
+        blurRegionsForSf = mAggregator.getBlurRegionsToDispatchToSf(
+                TEST_FRAME_NUMBER + 1, blurRegions, hasUpdates);
+        assertNotNull(blurRegionsForSf);
+        assertEquals(2, blurRegionsForSf.length);
+    }
+
+    @Test
+    public void testUiThreadUpdatesDoNotChangeStateOnRenderThread() {
+        // Updates for frame N
+        mDrawable.setBlurRadius(50);
+        mDrawable.setCornerRadius(1, 2, 3, 4);
+        mDrawable.setAlpha(20);
+
+        final BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+        assertEquals(1, blurRegions.length);
+        assertEquals(50, blurRegions[0].blurRadius);
+        assertEquals(20 / 255f, blurRegions[0].alpha);
+        assertEquals(1f, blurRegions[0].cornerRadiusTL);
+        assertEquals(2f, blurRegions[0].cornerRadiusTR);
+        assertEquals(3f, blurRegions[0].cornerRadiusBL);
+        assertEquals(4f, blurRegions[0].cornerRadiusBR);
+
+        // Updates for frame N+1
+        mDrawable.setBlurRadius(60);
+        mDrawable.setCornerRadius(10, 20, 30, 40);
+        mDrawable.setAlpha(40);
+
+        // Assert state for frame N is untouched
+        assertEquals(50, blurRegions[0].blurRadius);
+        assertEquals(20 / 255f, blurRegions[0].alpha);
+        assertEquals(1f, blurRegions[0].cornerRadiusTL);
+        assertEquals(2f, blurRegions[0].cornerRadiusTR);
+        assertEquals(3f, blurRegions[0].cornerRadiusBL);
+        assertEquals(4f, blurRegions[0].cornerRadiusBR);
+    }
+
+    @Test
+    public void testPositionUpdatesForFutureFramesAreNotAppliedForCurrentFrame() {
+        final BlurRegion[] blurRegions = mAggregator.getBlurRegionsCopyForRT();
+
+        mDrawable.mPositionUpdateListener.positionChanged(TEST_FRAME_NUMBER, 1, 2, 3, 4);
+        mDrawable.mPositionUpdateListener.positionChanged(TEST_FRAME_NUMBER + 1, 5, 6, 7, 8);
+
+        final float[][] blurRegionsForSf = mAggregator.getBlurRegionsToDispatchToSf(
+                TEST_FRAME_NUMBER, blurRegions, /* hasUiUpdates= */ false);
+        assertNotNull(blurRegionsForSf);
+        assertEquals(1, blurRegionsForSf.length);
+        // Assert state for first frame is not affected by update for second frame
+        assertEquals((float) TEST_BLUR_RADIUS, blurRegionsForSf[0][0]);
+        assertEquals(1f, blurRegionsForSf[0][2]);
+        assertEquals(2f, blurRegionsForSf[0][3]);
+        assertEquals(3f, blurRegionsForSf[0][4]);
+        assertEquals(4f, blurRegionsForSf[0][5]);
+
+        final float[][] blurRegionsForSfForNextFrame = mAggregator.getBlurRegionsToDispatchToSf(
+                TEST_FRAME_NUMBER + 1, blurRegions, /* hasUiUpdates= */ false);
+        assertNotNull(blurRegionsForSfForNextFrame);
+        assertEquals(1, blurRegionsForSfForNextFrame.length);
+        // Assert second frame updates are applied normally
+        assertEquals((float) TEST_BLUR_RADIUS, blurRegionsForSfForNextFrame[0][0]);
+        assertEquals(5f, blurRegionsForSfForNextFrame[0][2]);
+        assertEquals(6f, blurRegionsForSfForNextFrame[0][3]);
+        assertEquals(7f, blurRegionsForSfForNextFrame[0][4]);
+        assertEquals(8f, blurRegionsForSfForNextFrame[0][5]);
+    }
+
+}
diff --git a/core/tests/coretests/src/android/view/ScrollCaptureConnectionTest.java b/core/tests/coretests/src/android/view/ScrollCaptureConnectionTest.java
index b9cf1e4..516fb76 100644
--- a/core/tests/coretests/src/android/view/ScrollCaptureConnectionTest.java
+++ b/core/tests/coretests/src/android/view/ScrollCaptureConnectionTest.java
@@ -16,16 +16,12 @@
 
 package android.view;
 
-import static androidx.test.InstrumentationRegistry.getInstrumentation;
 import static androidx.test.InstrumentationRegistry.getTargetContext;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -35,6 +31,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Handler;
+import android.os.ICancellationSignal;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -42,9 +39,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.mockito.stubbing.Answer;
 
 /**
  * Tests of {@link ScrollCaptureConnection}.
@@ -56,261 +51,138 @@
     private final Point mPositionInWindow = new Point(1, 2);
     private final Rect mLocalVisibleRect = new Rect(2, 3, 4, 5);
     private final Rect mScrollBounds = new Rect(3, 4, 5, 6);
+    private final TestScrollCaptureCallback mCallback = new TestScrollCaptureCallback();
+
+    private ScrollCaptureTarget mTarget;
+    private ScrollCaptureConnection mConnection;
 
     private Handler mHandler;
-    private ScrollCaptureTarget mTarget1;
 
     @Mock
     private Surface mSurface;
     @Mock
-    private IScrollCaptureCallbacks mConnectionCallbacks;
+    private IScrollCaptureCallbacks mRemote;
     @Mock
-    private View mMockView1;
-    @Mock
-    private ScrollCaptureCallback mCallback1;
+    private View mView;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mHandler = new Handler(getTargetContext().getMainLooper());
+        when(mSurface.isValid()).thenReturn(true);
+        when(mView.getScrollCaptureHint()).thenReturn(View.SCROLL_CAPTURE_HINT_INCLUDE);
 
-        when(mMockView1.getHandler()).thenReturn(mHandler);
-        when(mMockView1.getScrollCaptureHint()).thenReturn(View.SCROLL_CAPTURE_HINT_INCLUDE);
-
-        mTarget1 = new ScrollCaptureTarget(
-                mMockView1, mLocalVisibleRect, mPositionInWindow, mCallback1);
-        mTarget1.setScrollBounds(mScrollBounds);
-    }
-
-    /** Test the DelayedAction timeout helper class works as expected. */
-    @Test
-    public void testDelayedAction() {
-        Runnable action = Mockito.mock(Runnable.class);
-        ScrollCaptureConnection.DelayedAction delayed =
-                new ScrollCaptureConnection.DelayedAction(mHandler, 100, action);
-        try {
-            Thread.sleep(200);
-        } catch (InterruptedException ex) {
-            /* ignore */
-        }
-        getInstrumentation().waitForIdleSync();
-        assertFalse(delayed.cancel());
-        assertFalse(delayed.timeoutNow());
-        verify(action, times(1)).run();
-    }
-
-    /** Test the DelayedAction cancel() */
-    @Test
-    public void testDelayedAction_cancel() {
-        Runnable action = Mockito.mock(Runnable.class);
-        ScrollCaptureConnection.DelayedAction delayed =
-                new ScrollCaptureConnection.DelayedAction(mHandler, 100, action);
-        try {
-            Thread.sleep(50);
-        } catch (InterruptedException ex) {
-            /* ignore */
-        }
-        assertTrue(delayed.cancel());
-        assertFalse(delayed.timeoutNow());
-        try {
-            Thread.sleep(200);
-        } catch (InterruptedException ex) {
-            /* ignore */
-        }
-        getInstrumentation().waitForIdleSync();
-        verify(action, never()).run();
-    }
-
-    /** Test the DelayedAction timeoutNow() - for testing only */
-    @Test
-    public void testDelayedAction_timeoutNow() {
-        Runnable action = Mockito.mock(Runnable.class);
-        ScrollCaptureConnection.DelayedAction delayed =
-                new ScrollCaptureConnection.DelayedAction(mHandler, 100, action);
-        try {
-            Thread.sleep(50);
-        } catch (InterruptedException ex) {
-            /* ignore */
-        }
-        assertTrue(delayed.timeoutNow());
-        assertFalse(delayed.cancel());
-        getInstrumentation().waitForIdleSync();
-        verify(action, times(1)).run();
+        mTarget = new ScrollCaptureTarget(mView, mLocalVisibleRect, mPositionInWindow, mCallback);
+        mTarget.setScrollBounds(mScrollBounds);
+        mConnection = new ScrollCaptureConnection(Runnable::run, mTarget, mRemote);
     }
 
     /** Test creating a client with valid info */
     @Test
     public void testConstruction() {
-        new ScrollCaptureConnection(mTarget1, mConnectionCallbacks);
+        ScrollCaptureTarget target = new ScrollCaptureTarget(
+                mView, mLocalVisibleRect, mPositionInWindow, mCallback);
+        target.setScrollBounds(new Rect(1, 2, 3, 4));
+        new ScrollCaptureConnection(Runnable::run, target, mRemote);
     }
 
     /** Test creating a client fails if arguments are not valid. */
     @Test
     public void testConstruction_requiresScrollBounds() {
         try {
-            mTarget1.setScrollBounds(null);
-            new ScrollCaptureConnection(mTarget1, mConnectionCallbacks);
+            mTarget.setScrollBounds(null);
+            new ScrollCaptureConnection(Runnable::run, mTarget, mRemote);
             fail("An exception was expected.");
         } catch (RuntimeException ex) {
             // Ignore, expected.
         }
     }
 
-    @SuppressWarnings("SameParameterValue")
-    private static Answer<Void> runRunnable(int arg) {
-        return invocation -> {
-            Runnable r = invocation.getArgument(arg);
-            r.run();
-            return null;
-        };
-    }
-
-    @SuppressWarnings("SameParameterValue")
-    private static Answer<Void> reportBufferSent(int sessionArg, long frameNum, Rect capturedArea) {
-        return invocation -> {
-            ScrollCaptureSession session = invocation.getArgument(sessionArg);
-            session.notifyBufferSent(frameNum, capturedArea);
-            return null;
-        };
-    }
-
     /** @see ScrollCaptureConnection#startCapture(Surface) */
     @Test
     public void testStartCapture() throws Exception {
-        final ScrollCaptureConnection connection = new ScrollCaptureConnection(mTarget1,
-                mConnectionCallbacks);
+        mConnection.startCapture(mSurface);
 
-        // Have the session start accepted immediately
-        doAnswer(runRunnable(1)).when(mCallback1)
-                .onScrollCaptureStart(any(ScrollCaptureSession.class), any(Runnable.class));
-        connection.startCapture(mSurface);
-        getInstrumentation().waitForIdleSync();
+        mCallback.completeStartRequest();
+        assertTrue(mConnection.isStarted());
 
-        verify(mCallback1, times(1))
-                .onScrollCaptureStart(any(ScrollCaptureSession.class), any(Runnable.class));
-        verify(mConnectionCallbacks, times(1)).onCaptureStarted();
-        verifyNoMoreInteractions(mConnectionCallbacks);
+        verify(mRemote, times(1)).onCaptureStarted();
+        verifyNoMoreInteractions(mRemote);
     }
 
     @Test
-    public void testStartCaptureTimeout() throws Exception {
-        final ScrollCaptureConnection connection = new ScrollCaptureConnection(mTarget1,
-                mConnectionCallbacks);
-        connection.startCapture(mSurface);
+    public void testStartCapture_cancellation() throws Exception {
+        ICancellationSignal signal = mConnection.startCapture(mSurface);
+        signal.cancel();
 
-        // Force timeout to fire
-        connection.getTimeoutAction().timeoutNow();
+        mCallback.completeStartRequest();
+        assertFalse(mConnection.isStarted());
 
-        getInstrumentation().waitForIdleSync();
-        verify(mCallback1, times(1)).onScrollCaptureEnd(any(Runnable.class));
-    }
-
-    private void startCapture(ScrollCaptureConnection connection) throws Exception {
-        doAnswer(runRunnable(1)).when(mCallback1)
-                .onScrollCaptureStart(any(ScrollCaptureSession.class), any(Runnable.class));
-        connection.startCapture(mSurface);
-        getInstrumentation().waitForIdleSync();
-        reset(mCallback1, mConnectionCallbacks);
+        verifyNoMoreInteractions(mRemote);
     }
 
     /** @see ScrollCaptureConnection#requestImage(Rect) */
     @Test
     public void testRequestImage() throws Exception {
-        final ScrollCaptureConnection connection = new ScrollCaptureConnection(mTarget1,
-                mConnectionCallbacks);
-        startCapture(connection);
+        mConnection.startCapture(mSurface);
+        mCallback.completeStartRequest();
+        reset(mRemote);
 
-        // Stub the callback to complete the request immediately
-        doAnswer(reportBufferSent(/* sessionArg */ 0, /* frameNum */ 1L, new Rect(1, 2, 3, 4)))
-                .when(mCallback1)
-                .onScrollCaptureImageRequest(any(ScrollCaptureSession.class), any(Rect.class));
+        mConnection.requestImage(new Rect(1, 2, 3, 4));
+        mCallback.completeImageRequest(new Rect(1, 2, 3, 4));
 
-        // Make the inbound binder call
-        connection.requestImage(new Rect(1, 2, 3, 4));
-
-        // Wait for handler thread dispatch
-        getInstrumentation().waitForIdleSync();
-        verify(mCallback1, times(1)).onScrollCaptureImageRequest(
-                any(ScrollCaptureSession.class), eq(new Rect(1, 2, 3, 4)));
-
-        // Wait for binder thread dispatch
-        getInstrumentation().waitForIdleSync();
-        verify(mConnectionCallbacks, times(1))
-                .onCaptureBufferSent(eq(1L), eq(new Rect(1, 2, 3, 4)));
-
-        verifyNoMoreInteractions(mCallback1, mConnectionCallbacks);
+        verify(mRemote, times(1))
+                .onImageRequestCompleted(eq(0), eq(new Rect(1, 2, 3, 4)));
+        verifyNoMoreInteractions(mRemote);
     }
 
     @Test
-    public void testRequestImageTimeout() throws Exception {
-        final ScrollCaptureConnection connection = new ScrollCaptureConnection(mTarget1,
-                mConnectionCallbacks);
-        startCapture(connection);
+    public void testRequestImage_cancellation() throws Exception {
+        mConnection.startCapture(mSurface);
+        mCallback.completeStartRequest();
+        reset(mRemote);
 
-        // Make the inbound binder call
-        connection.requestImage(new Rect(1, 2, 3, 4));
+        ICancellationSignal signal = mConnection.requestImage(new Rect(1, 2, 3, 4));
+        signal.cancel();
+        mCallback.completeImageRequest(new Rect(1, 2, 3, 4));
 
-        // Wait for handler thread dispatch
-        getInstrumentation().waitForIdleSync();
-        verify(mCallback1, times(1)).onScrollCaptureImageRequest(
-                any(ScrollCaptureSession.class), eq(new Rect(1, 2, 3, 4)));
-
-        // Force timeout to fire
-        connection.getTimeoutAction().timeoutNow();
-        getInstrumentation().waitForIdleSync();
-
-        // (callback not stubbed, does nothing)
-        // Timeout triggers request to end capture
-        verify(mCallback1, times(1)).onScrollCaptureEnd(any(Runnable.class));
-        verifyNoMoreInteractions(mCallback1, mConnectionCallbacks);
+        verifyNoMoreInteractions(mRemote);
     }
 
     /** @see ScrollCaptureConnection#endCapture() */
     @Test
     public void testEndCapture() throws Exception {
-        final ScrollCaptureConnection connection = new ScrollCaptureConnection(mTarget1,
-                mConnectionCallbacks);
-        startCapture(connection);
+        mConnection.startCapture(mSurface);
+        mCallback.completeStartRequest();
+        reset(mRemote);
 
-        // Stub the callback to complete the request immediately
-        doAnswer(runRunnable(0))
-                .when(mCallback1)
-                .onScrollCaptureEnd(any(Runnable.class));
+        mConnection.endCapture();
+        mCallback.completeEndRequest();
 
-        // Make the inbound binder call
-        connection.endCapture();
+        // And the reply is sent
+        verify(mRemote, times(1)).onCaptureEnded();
+        verifyNoMoreInteractions(mRemote);
+    }
 
-        // Wait for handler thread dispatch
-        getInstrumentation().waitForIdleSync();
-        verify(mCallback1, times(1)).onScrollCaptureEnd(any(Runnable.class));
+    /** @see ScrollCaptureConnection#endCapture() */
+    @Test
+    public void testEndCapture_cancellation() throws Exception {
+        mConnection.startCapture(mSurface);
+        mCallback.completeStartRequest();
+        reset(mRemote);
 
-        // Wait for binder thread dispatch
-        getInstrumentation().waitForIdleSync();
-        verify(mConnectionCallbacks, times(1)).onConnectionClosed();
+        ICancellationSignal signal = mConnection.endCapture();
+        signal.cancel();
+        mCallback.completeEndRequest();
 
-        verifyNoMoreInteractions(mCallback1, mConnectionCallbacks);
+        verifyNoMoreInteractions(mRemote);
     }
 
     @Test
-    public void testEndCaptureTimeout() throws Exception {
-        final ScrollCaptureConnection connection = new ScrollCaptureConnection(mTarget1,
-                mConnectionCallbacks);
-        startCapture(connection);
-
-        // Make the inbound binder call
-        connection.endCapture();
-
-        // Wait for handler thread dispatch
-        getInstrumentation().waitForIdleSync();
-        verify(mCallback1, times(1)).onScrollCaptureEnd(any(Runnable.class));
-
-        // Force timeout to fire
-        connection.getTimeoutAction().timeoutNow();
-
-        // Wait for binder thread dispatch
-        getInstrumentation().waitForIdleSync();
-        verify(mConnectionCallbacks, times(1)).onConnectionClosed();
-
-        verifyNoMoreInteractions(mCallback1, mConnectionCallbacks);
+    public void testClose() throws Exception {
+        mConnection.close();
+        assertFalse(mConnection.isConnected());
+        verifyNoMoreInteractions(mRemote);
     }
+
 }
diff --git a/core/tests/coretests/src/android/view/ScrollCaptureSearchResultsTest.java b/core/tests/coretests/src/android/view/ScrollCaptureSearchResultsTest.java
new file mode 100644
index 0000000..cc229e1
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ScrollCaptureSearchResultsTest.java
@@ -0,0 +1,415 @@
+/*
+ * 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 android.view;
+
+import static androidx.test.InstrumentationRegistry.getTargetContext;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.CancellationSignal;
+import android.os.SystemClock;
+
+import androidx.annotation.NonNull;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+/**
+ * Tests of {@link ScrollCaptureTargetSelector}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class ScrollCaptureSearchResultsTest {
+
+
+    private static final Rect EMPTY_RECT = new Rect();
+    private static final String TAG = "Test";
+
+    private final Executor mDirectExec = Runnable::run;
+    private Executor mBgExec;
+
+    @Before
+    public void setUp() {
+        mBgExec = Executors.newSingleThreadExecutor();
+    }
+
+    @Test
+    public void testNoTargets() {
+        ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(mDirectExec);
+        assertTrue(results.isComplete());
+
+        assertNull("Expected null due to empty queue", results.getTopResult());
+    }
+
+    @Test
+    public void testNoValidTargets() {
+        ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(mDirectExec);
+
+        FakeScrollCaptureCallback callback1 = new FakeScrollCaptureCallback(mDirectExec);
+        callback1.setScrollBounds(EMPTY_RECT);
+        ScrollCaptureTarget target1 = createTarget(callback1, new Rect(20, 30, 40, 50),
+                new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
+
+        // Supplies scrollBounds = empty rect
+        FakeScrollCaptureCallback callback2 = new FakeScrollCaptureCallback(mDirectExec);
+        callback2.setScrollBounds(EMPTY_RECT);
+        ScrollCaptureTarget target2 = createTarget(callback2, new Rect(20, 30, 40, 50),
+                new Point(0, 20), View.SCROLL_CAPTURE_HINT_INCLUDE);
+
+        results.addTarget(target1);
+        results.addTarget(target2);
+
+        assertTrue(results.isComplete());
+        assertNull("Expected null due to no valid targets", results.getTopResult());
+    }
+
+    @Test
+    public void testSingleTarget() {
+        ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(mDirectExec);
+        FakeScrollCaptureCallback callback = new FakeScrollCaptureCallback(mDirectExec);
+        ScrollCaptureTarget target = createTarget(callback,
+                new Rect(20, 30, 40, 50), new Point(10, 10),
+                View.SCROLL_CAPTURE_HINT_AUTO);
+        callback.setScrollBounds(new Rect(2, 2, 18, 18));
+
+        results.addTarget(target);
+        assertTrue(results.isComplete());
+
+        ScrollCaptureTarget result = results.getTopResult();
+        assertSame("Excepted the same target as a result", target, result);
+        assertEquals("result has wrong scroll bounds",
+                new Rect(2, 2, 18, 18), result.getScrollBounds());
+    }
+
+    @Test
+    public void testSingleTarget_backgroundThread() throws InterruptedException {
+        FakeScrollCaptureCallback callback1 = new FakeScrollCaptureCallback(mBgExec);
+        ScrollCaptureTarget target1 = createTarget(callback1,
+                new Rect(20, 30, 40, 50), new Point(10, 10),
+                View.SCROLL_CAPTURE_HINT_AUTO);
+        callback1.setDelay(100);
+        callback1.setScrollBounds(new Rect(2, 2, 18, 18));
+
+        ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(mDirectExec);
+        results.addTarget(target1);
+
+        CountDownLatch latch = new CountDownLatch(1);
+        results.setOnCompleteListener(latch::countDown);
+        if (!latch.await(200, TimeUnit.MILLISECONDS)) {
+            fail("onComplete listener was expected");
+        }
+
+        ScrollCaptureTarget result = results.getTopResult();
+        assertSame("Excepted the single target1 as a result", target1, result);
+        assertEquals("Result has wrong scroll bounds",
+                new Rect(2, 2, 18, 18), result.getScrollBounds());
+    }
+
+    @Test
+    public void testRanking() {
+
+        // 1 - Empty
+        FakeScrollCaptureCallback callback1 = new FakeScrollCaptureCallback(mDirectExec);
+        callback1.setScrollBounds(EMPTY_RECT);
+        ViewGroup targetView1 = new FakeView(getTargetContext(), 0, 0, 60, 60, 1);
+        ScrollCaptureTarget target1 = createTargetWithView(targetView1, callback1,
+                new Rect(0, 0, 60, 60), new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
+
+        // 2 - 10x10 + HINT_INCLUDE
+        FakeScrollCaptureCallback callback2 = new FakeScrollCaptureCallback(mDirectExec);
+        callback2.setScrollBounds(new Rect(0, 0, 10, 10));
+        ViewGroup targetView2 = new FakeView(getTargetContext(), 0, 0, 60, 60, 2);
+        ScrollCaptureTarget target2 = createTargetWithView(targetView2, callback2,
+                 new Rect(0, 0, 60, 60), new Point(0, 0), View.SCROLL_CAPTURE_HINT_INCLUDE);
+
+        // 3 - 20x20 + AUTO
+        FakeScrollCaptureCallback callback3 = new FakeScrollCaptureCallback(mDirectExec);
+        callback3.setScrollBounds(new Rect(0, 0, 20, 20));
+        ViewGroup targetView3 = new FakeView(getTargetContext(), 0, 0, 60, 60, 3);
+        ScrollCaptureTarget target3 = createTargetWithView(targetView3, callback3,
+                new Rect(0, 0, 60, 60), new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
+
+        // 4 - 30x30 + AUTO
+        FakeScrollCaptureCallback callback4 = new FakeScrollCaptureCallback(mDirectExec);
+        callback4.setScrollBounds(new Rect(0, 0, 10, 10));
+        ViewGroup targetView4 = new FakeView(getTargetContext(), 0, 0, 60, 60, 4);
+        ScrollCaptureTarget target4 = createTargetWithView(targetView4, callback4,
+                new Rect(0, 0, 60, 60), new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
+
+        // 5 - 10x10 + child of #4
+        FakeScrollCaptureCallback callback5 = new FakeScrollCaptureCallback(mDirectExec);
+        callback5.setScrollBounds(new Rect(0, 0, 10, 10));
+        ViewGroup targetView5 = new FakeView(getTargetContext(), 0, 0, 60, 60, 5);
+        ScrollCaptureTarget target5 = createTargetWithView(targetView5, callback5,
+                new Rect(0, 0, 60, 60), new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
+        targetView4.addView(targetView5);
+
+        // 6 - 20x20 + child of #4
+        FakeScrollCaptureCallback callback6 = new FakeScrollCaptureCallback(mDirectExec);
+        callback6.setScrollBounds(new Rect(0, 0, 20, 20));
+        ViewGroup targetView6 = new FakeView(getTargetContext(), 0, 0, 60, 60, 6);
+        ScrollCaptureTarget target6 = createTargetWithView(targetView6, callback6,
+                new Rect(0, 0, 60, 60), new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
+        targetView4.addView(targetView6);
+
+        ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(mDirectExec);
+        results.addTarget(target1);
+        results.addTarget(target2);
+        results.addTarget(target3);
+        results.addTarget(target4);
+        results.addTarget(target5);
+        results.addTarget(target6);
+        assertTrue(results.isComplete());
+
+        // Verify "top" result
+        assertEquals(target2, results.getTopResult());
+
+        // Verify priority ("best" first)
+        assertThat(results.getTargets())
+                .containsExactly(
+                        target2,
+                        target6,
+                        target5,
+                        target4,
+                        target3,
+                        target1);
+    }
+
+    /**
+     * If a timeout expires, late results are ignored.
+     */
+    @Test
+    public void testTimeout() {
+        ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(mDirectExec);
+
+        // callback 1, 10x10, hint=AUTO, responds after 100ms from bg thread
+        FakeScrollCaptureCallback callback1 = new FakeScrollCaptureCallback(mBgExec);
+        callback1.setScrollBounds(new Rect(5, 5, 15, 15));
+        callback1.setDelay(100);
+        ScrollCaptureTarget target1 = createTarget(
+                callback1, new Rect(20, 30, 40, 50), new Point(10, 10),
+                View.SCROLL_CAPTURE_HINT_AUTO);
+        results.addTarget(target1);
+
+        // callback 2, 20x20, hint=AUTO, responds after 5s from bg thread
+        FakeScrollCaptureCallback callback2 = new FakeScrollCaptureCallback(mBgExec);
+        callback2.setScrollBounds(new Rect(0, 0, 20, 20));
+        callback2.setDelay(1000);
+        ScrollCaptureTarget target2 = createTarget(
+                callback2, new Rect(20, 30, 40, 50), new Point(10, 10),
+                View.SCROLL_CAPTURE_HINT_AUTO);
+        results.addTarget(target2);
+
+        // callback 3, 20x20, hint=INCLUDE, responds after 10s from bg thread
+        FakeScrollCaptureCallback callback3 = new FakeScrollCaptureCallback(mBgExec);
+        callback3.setScrollBounds(new Rect(0, 0, 20, 20));
+        callback3.setDelay(1500);
+        ScrollCaptureTarget target3 = createTarget(
+                callback3, new Rect(20, 30, 40, 50), new Point(10, 10),
+                View.SCROLL_CAPTURE_HINT_INCLUDE);
+        results.addTarget(target3);
+
+        // callback 1 will be received
+        // callback 2 & 3 will be ignored due to timeout
+        SystemClock.sleep(500);
+        results.finish();
+
+        ScrollCaptureTarget result = results.getTopResult();
+        assertSame("Expected target1 as the result, due to timeouts of others", target1, result);
+        assertEquals("callback1 should have been called",
+                1, callback1.getOnScrollCaptureSearchCount());
+        assertEquals("callback2 should have been called",
+                1, callback2.getOnScrollCaptureSearchCount());
+        assertEquals("callback3 should have been called",
+                1, callback3.getOnScrollCaptureSearchCount());
+
+        assertEquals("result has wrong scroll bounds",
+                new Rect(5, 5, 15, 15), result.getScrollBounds());
+        assertNull("target2 should not have been updated",
+                target2.getScrollBounds());
+        assertNull("target3 should not have been updated",
+                target3.getScrollBounds());
+    }
+
+    @Test
+    public void testWithCallbackMultipleReplies() {
+        // Calls response methods 3 times each
+        ScrollCaptureCallback callback1 = new CallbackStub() {
+            @Override
+            public void onScrollCaptureSearch(@NonNull CancellationSignal signal,
+                    @NonNull Consumer<Rect> onReady) {
+                onReady.accept(new Rect(1, 2, 3, 4));
+                onReady.accept(new Rect(9, 10, 11, 12));
+            }
+        };
+
+        ScrollCaptureTarget target1 = createTarget(callback1, new Rect(20, 30, 40, 50),
+                new Point(10, 10), View.SCROLL_CAPTURE_HINT_AUTO);
+
+        ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(mDirectExec);
+        results.addTarget(target1);
+        assertTrue(results.isComplete());
+
+        ScrollCaptureTarget result = results.getTopResult();
+        assertSame("Expected target1", target1, result);
+        assertEquals("result has wrong scroll bounds",
+                new Rect(1, 2, 3, 4), result.getScrollBounds());
+    }
+
+    private void setupTargetView(View view, Rect localVisibleRect, int scrollCaptureHint) {
+        view.setScrollCaptureHint(scrollCaptureHint);
+        view.onVisibilityAggregated(true);
+        // Treat any offset as padding, outset localVisibleRect on all sides and use this as
+        // child bounds
+        Rect bounds = new Rect(localVisibleRect);
+        bounds.inset(-bounds.left, -bounds.top, bounds.left, bounds.top);
+        view.layout(bounds.left, bounds.top, bounds.right, bounds.bottom);
+        view.onVisibilityAggregated(true);
+    }
+
+    private ScrollCaptureTarget createTarget(ScrollCaptureCallback callback, Rect localVisibleRect,
+            Point positionInWindow, int scrollCaptureHint) {
+        View mockView = new View(getTargetContext());
+        return createTargetWithView(mockView, callback, localVisibleRect, positionInWindow,
+                scrollCaptureHint);
+    }
+
+    private ScrollCaptureTarget createTargetWithView(View view, ScrollCaptureCallback callback,
+            Rect localVisibleRect, Point positionInWindow, int scrollCaptureHint) {
+        setupTargetView(view, localVisibleRect, scrollCaptureHint);
+        return new ScrollCaptureTarget(view, localVisibleRect, positionInWindow, callback);
+    }
+
+
+    static class FakeView extends ViewGroup implements ViewParent {
+        FakeView(Context context, int l, int t, int r, int b, int id) {
+            super(context);
+            layout(l, t, r, b);
+            setId(id);
+        }
+
+        @Override
+        protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        }
+    }
+
+    static class FakeScrollCaptureCallback implements ScrollCaptureCallback {
+        private final Executor mExecutor;
+        private Rect mScrollBounds;
+        private long mDelayMillis;
+        private int mOnScrollCaptureSearchCount;
+        FakeScrollCaptureCallback(Executor executor) {
+            mExecutor = executor;
+        }
+        public int getOnScrollCaptureSearchCount() {
+            return mOnScrollCaptureSearchCount;
+        }
+
+        @Override
+        public void onScrollCaptureSearch(CancellationSignal signal, Consumer<Rect> onReady) {
+            mOnScrollCaptureSearchCount++;
+            run(() -> {
+                Rect b = getScrollBounds();
+                onReady.accept(b);
+            });
+        }
+
+        @Override
+        public void onScrollCaptureStart(ScrollCaptureSession session, CancellationSignal signal,
+                Runnable onReady) {
+            run(onReady);
+        }
+
+        @Override
+        public void onScrollCaptureImageRequest(ScrollCaptureSession session,
+                CancellationSignal signal, Rect captureArea, Consumer<Rect> onReady) {
+            run(() -> onReady.accept(captureArea));
+        }
+
+        @Override
+        public void onScrollCaptureEnd(Runnable onReady) {
+            run(onReady);
+        }
+
+        public void setScrollBounds(@Nullable Rect scrollBounds) {
+            mScrollBounds = scrollBounds;
+        }
+
+        public void setDelay(long delayMillis) {
+            mDelayMillis = delayMillis;
+        }
+
+        protected Rect getScrollBounds() {
+            return mScrollBounds;
+        }
+
+        protected void run(Runnable r) {
+            mExecutor.execute(() -> {
+                delay();
+                r.run();
+            });
+        }
+
+        protected void delay() {
+            if (mDelayMillis > 0) {
+                try {
+                    Thread.sleep(mDelayMillis);
+                } catch (InterruptedException e) {
+                    // Ignore
+                }
+            }
+        }
+    }
+    static class CallbackStub implements ScrollCaptureCallback {
+        @Override
+        public void onScrollCaptureSearch(@NonNull CancellationSignal signal,
+                @NonNull Consumer<Rect> onReady) {
+        }
+
+        @Override
+        public void onScrollCaptureStart(@NonNull ScrollCaptureSession session,
+                @NonNull CancellationSignal signal, @NonNull Runnable onReady) {
+        }
+
+        @Override
+        public void onScrollCaptureImageRequest(@NonNull ScrollCaptureSession session,
+                @NonNull CancellationSignal signal, @NonNull Rect captureArea,
+                Consumer<Rect> onReady) {
+        }
+
+        @Override
+        public void onScrollCaptureEnd(@NonNull Runnable onReady) {
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/view/ScrollCaptureTargetResolverTest.java b/core/tests/coretests/src/android/view/ScrollCaptureTargetResolverTest.java
deleted file mode 100644
index 8b21b8e..0000000
--- a/core/tests/coretests/src/android/view/ScrollCaptureTargetResolverTest.java
+++ /dev/null
@@ -1,498 +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 android.view;
-
-import static androidx.test.InstrumentationRegistry.getTargetContext;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.os.Handler;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.LinkedList;
-import java.util.function.Consumer;
-
-/**
- * Tests of {@link ScrollCaptureTargetResolver}.
- */
-@RunWith(AndroidJUnit4.class)
-public class ScrollCaptureTargetResolverTest {
-
-    private static final long TEST_TIMEOUT_MS = 2000;
-    private static final long RESOLVER_TIMEOUT_MS = 1000;
-
-    private Handler mHandler;
-    private TargetConsumer mTargetConsumer;
-
-    @Before
-    public void setUp() {
-        mTargetConsumer = new TargetConsumer();
-        mHandler = new Handler(getTargetContext().getMainLooper());
-    }
-
-    @Test(timeout = TEST_TIMEOUT_MS)
-    public void testEmptyQueue() throws InterruptedException {
-        ScrollCaptureTargetResolver resolver = new ScrollCaptureTargetResolver(new LinkedList<>());
-        resolver.start(mHandler, RESOLVER_TIMEOUT_MS, mTargetConsumer);
-
-        // Test only
-        resolver.waitForResult();
-
-        ScrollCaptureTarget result = mTargetConsumer.getLastValue();
-        assertNull("Expected null due to empty queue", result);
-    }
-
-    @Test(timeout = TEST_TIMEOUT_MS)
-    public void testNoValidTargets() throws InterruptedException {
-        LinkedList<ScrollCaptureTarget> targetQueue = new LinkedList<>();
-
-        // Supplies scrollBounds = null
-        FakeScrollCaptureCallback callback1 = new FakeScrollCaptureCallback();
-        callback1.setScrollBounds(null);
-        ScrollCaptureTarget target1 = createTarget(callback1, new Rect(20, 30, 40, 50),
-                new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
-
-        // Supplies scrollBounds = empty rect
-        FakeScrollCaptureCallback callback2 = new FakeScrollCaptureCallback();
-        callback2.setScrollBounds(new Rect());
-        ScrollCaptureTarget target2 = createTarget(callback2, new Rect(20, 30, 40, 50),
-                new Point(0, 20), View.SCROLL_CAPTURE_HINT_INCLUDE);
-
-        targetQueue.add(target1);
-        targetQueue.add(target2);
-
-        ScrollCaptureTargetResolver resolver = new ScrollCaptureTargetResolver(targetQueue);
-        resolver.start(mHandler, RESOLVER_TIMEOUT_MS, mTargetConsumer);
-
-        // Test only
-        resolver.waitForResult();
-
-        ScrollCaptureTarget result = mTargetConsumer.getLastValue();
-        assertNull("Expected null due to no valid targets", result);
-    }
-
-    @Test(timeout = TEST_TIMEOUT_MS)
-    public void testSingleTarget() throws InterruptedException {
-        FakeScrollCaptureCallback callback = new FakeScrollCaptureCallback();
-        ScrollCaptureTarget target = createTarget(callback,
-                new Rect(20, 30, 40, 50), new Point(10, 10),
-                View.SCROLL_CAPTURE_HINT_AUTO);
-        callback.setScrollBounds(new Rect(2, 2, 18, 18));
-
-        LinkedList<ScrollCaptureTarget> targetQueue = new LinkedList<>();
-        targetQueue.add(target);
-        ScrollCaptureTargetResolver resolver = new ScrollCaptureTargetResolver(targetQueue);
-        resolver.start(mHandler, RESOLVER_TIMEOUT_MS, mTargetConsumer);
-
-        // Test only
-        resolver.waitForResult();
-
-        ScrollCaptureTarget result = mTargetConsumer.getLastValue();
-        assertSame("Excepted the same target as a result", target, result);
-        assertEquals("result has wrong scroll bounds",
-                new Rect(2, 2, 18, 18), result.getScrollBounds());
-    }
-
-    @Test(timeout = TEST_TIMEOUT_MS)
-    public void testSingleTarget_backgroundThread() throws InterruptedException {
-        BackgroundTestCallback callback1 = new BackgroundTestCallback();
-        ScrollCaptureTarget target1 = createTarget(callback1,
-                new Rect(20, 30, 40, 50), new Point(10, 10),
-                View.SCROLL_CAPTURE_HINT_AUTO);
-        callback1.setDelay(100);
-        callback1.setScrollBounds(new Rect(2, 2, 18, 18));
-
-        LinkedList<ScrollCaptureTarget> targetQueue = new LinkedList<>();
-        targetQueue.add(target1);
-
-        ScrollCaptureTargetResolver resolver = new ScrollCaptureTargetResolver(targetQueue);
-        resolver.start(mHandler, RESOLVER_TIMEOUT_MS, mTargetConsumer);
-
-        // Test only
-        resolver.waitForResult();
-
-        ScrollCaptureTarget result = mTargetConsumer.getLastValue();
-        assertSame("Excepted the single target1 as a result", target1, result);
-        assertEquals("Result has wrong scroll bounds",
-                new Rect(2, 2, 18, 18), result.getScrollBounds());
-    }
-
-    @Test(timeout = TEST_TIMEOUT_MS)
-    public void testPreferNonEmptyBounds() throws InterruptedException {
-        LinkedList<ScrollCaptureTarget> targetQueue = new LinkedList<>();
-
-        FakeScrollCaptureCallback callback1 = new FakeScrollCaptureCallback();
-        callback1.setScrollBounds(new Rect());
-        ScrollCaptureTarget target1 = createTarget(callback1, new Rect(20, 30, 40, 50),
-                new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
-
-        FakeScrollCaptureCallback callback2 = new FakeScrollCaptureCallback();
-        callback2.setScrollBounds(new Rect(0, 0, 20, 20));
-        ScrollCaptureTarget target2 = createTarget(callback2, new Rect(20, 30, 40, 50),
-                new Point(0, 20), View.SCROLL_CAPTURE_HINT_INCLUDE);
-
-        FakeScrollCaptureCallback callback3 = new FakeScrollCaptureCallback();
-        callback3.setScrollBounds(null);
-        ScrollCaptureTarget target3 = createTarget(callback3, new Rect(20, 30, 40, 50),
-                new Point(0, 40), View.SCROLL_CAPTURE_HINT_AUTO);
-
-        targetQueue.add(target1);
-        targetQueue.add(target2); // scrollBounds not null or empty()
-        targetQueue.add(target3);
-
-        ScrollCaptureTargetResolver resolver = new ScrollCaptureTargetResolver(targetQueue);
-        resolver.start(mHandler, RESOLVER_TIMEOUT_MS, mTargetConsumer);
-        resolver.waitForResult();
-
-        ScrollCaptureTarget result = mTargetConsumer.getLastValue();
-        assertEquals("Expected " + target2 + " as a result", target2, result);
-        assertEquals("result has wrong scroll bounds",
-                new Rect(0, 0, 20, 20), result.getScrollBounds());
-    }
-
-    @Test(timeout = TEST_TIMEOUT_MS)
-    public void testPreferHintInclude() throws InterruptedException {
-        LinkedList<ScrollCaptureTarget> targetQueue = new LinkedList<>();
-
-        FakeScrollCaptureCallback callback1 = new FakeScrollCaptureCallback();
-        callback1.setScrollBounds(new Rect(0, 0, 20, 20));
-        ScrollCaptureTarget target1 = createTarget(callback1, new Rect(20, 30, 40, 50),
-                new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
-
-        FakeScrollCaptureCallback callback2 = new FakeScrollCaptureCallback();
-        callback2.setScrollBounds(new Rect(1, 1, 19, 19));
-        ScrollCaptureTarget target2 = createTarget(callback2, new Rect(20, 30, 40, 50),
-                new Point(0, 20), View.SCROLL_CAPTURE_HINT_INCLUDE);
-
-        FakeScrollCaptureCallback callback3 = new FakeScrollCaptureCallback();
-        callback3.setScrollBounds(new Rect(2, 2, 18, 18));
-        ScrollCaptureTarget target3 = createTarget(callback3, new Rect(20, 30, 40, 50),
-                new Point(0, 40), View.SCROLL_CAPTURE_HINT_AUTO);
-
-        targetQueue.add(target1);
-        targetQueue.add(target2); // * INCLUDE > AUTO
-        targetQueue.add(target3);
-
-        ScrollCaptureTargetResolver resolver = new ScrollCaptureTargetResolver(targetQueue);
-        resolver.start(mHandler, RESOLVER_TIMEOUT_MS, mTargetConsumer);
-
-        resolver.waitForResult();
-
-        ScrollCaptureTarget result = mTargetConsumer.getLastValue();
-        assertEquals("input = " + targetQueue + " Expected " + target2
-                + " as the result, due to hint=INCLUDE", target2, result);
-        assertEquals("result has wrong scroll bounds",
-                new Rect(1, 1, 19, 19), result.getScrollBounds());
-    }
-
-    @Test(timeout = TEST_TIMEOUT_MS)
-    public void testDescendantPreferred() throws InterruptedException {
-        LinkedList<ScrollCaptureTarget> targetQueue = new LinkedList<>();
-
-        ViewGroup targetView1 = new FakeRootView(getTargetContext(), 0, 0, 60, 60); // 60x60
-        ViewGroup targetView2 = new FakeRootView(getTargetContext(), 20, 30, 40, 50); // 20x20
-        ViewGroup targetView3 = new FakeRootView(getTargetContext(), 5, 5, 15, 15); // 10x10
-
-        targetView1.addView(targetView2);
-        targetView2.addView(targetView3);
-
-        // Create first target with an unrelated parent
-        FakeScrollCaptureCallback callback1 = new FakeScrollCaptureCallback();
-        callback1.setScrollBounds(new Rect(0, 0, 60, 60));
-        ScrollCaptureTarget target1 = createTargetWithView(targetView1, callback1,
-                new Rect(0, 0, 60, 60),
-                new Point(0, 0), View.SCROLL_CAPTURE_HINT_AUTO);
-
-        // Create second target associated with a view within parent2
-        FakeScrollCaptureCallback callback2 = new FakeScrollCaptureCallback();
-        callback2.setScrollBounds(new Rect(0, 0, 20, 20));
-        ScrollCaptureTarget target2 = createTargetWithView(targetView2, callback2,
-                new Rect(0, 0, 20, 20),
-                new Point(20, 30), View.SCROLL_CAPTURE_HINT_AUTO);
-
-        // Create third target associated with a view within parent3
-        FakeScrollCaptureCallback callback3 = new FakeScrollCaptureCallback();
-        callback3.setScrollBounds(new Rect(0, 0, 15, 15));
-        ScrollCaptureTarget target3 = createTargetWithView(targetView3, callback3,
-                new Rect(0, 0, 15, 15),
-                new Point(25, 35), View.SCROLL_CAPTURE_HINT_AUTO);
-
-        targetQueue.add(target1); // auto, 60x60
-        targetQueue.add(target2); // auto, 20x20
-        targetQueue.add(target3); // auto, 15x15 <- innermost scrollable
-
-        ScrollCaptureTargetResolver resolver = new ScrollCaptureTargetResolver(targetQueue);
-        resolver.start(mHandler, RESOLVER_TIMEOUT_MS, mTargetConsumer);
-
-        // Test only
-        resolver.waitForResult();
-
-        ScrollCaptureTarget result = mTargetConsumer.getLastValue();
-        assertSame("Expected target3 as the result, due to relation", target3, result);
-        assertEquals("result has wrong scroll bounds",
-                new Rect(0, 0, 15, 15), result.getScrollBounds());
-    }
-
-    /**
-     * If a timeout expires, late results are ignored.
-     */
-    @Test(timeout = TEST_TIMEOUT_MS)
-    public void testTimeout() throws InterruptedException {
-        LinkedList<ScrollCaptureTarget> targetQueue = new LinkedList<>();
-
-        // callback 1, 10x10, hint=AUTO, responds immediately from bg thread
-        BackgroundTestCallback callback1 = new BackgroundTestCallback();
-        callback1.setScrollBounds(new Rect(5, 5, 15, 15));
-        ScrollCaptureTarget target1 = createTarget(
-                callback1, new Rect(20, 30, 40, 50), new Point(10, 10),
-                View.SCROLL_CAPTURE_HINT_AUTO);
-        targetQueue.add(target1);
-
-        // callback 2, 20x20, hint=AUTO, responds after 5s from bg thread
-        BackgroundTestCallback callback2 = new BackgroundTestCallback();
-        callback2.setScrollBounds(new Rect(0, 0, 20, 20));
-        callback2.setDelay(5000);
-        ScrollCaptureTarget target2 = createTarget(
-                callback2, new Rect(20, 30, 40, 50), new Point(10, 10),
-                View.SCROLL_CAPTURE_HINT_AUTO);
-        targetQueue.add(target2);
-
-        // callback 3, 20x20, hint=INCLUDE, responds after 10s from bg thread
-        BackgroundTestCallback callback3 = new BackgroundTestCallback();
-        callback3.setScrollBounds(new Rect(0, 0, 20, 20));
-        callback3.setDelay(10000);
-        ScrollCaptureTarget target3 = createTarget(
-                callback3, new Rect(20, 30, 40, 50), new Point(10, 10),
-                View.SCROLL_CAPTURE_HINT_INCLUDE);
-        targetQueue.add(target3);
-
-        // callback 1 will be received
-        // callback 2 & 3 will be ignored due to timeout
-
-        ScrollCaptureTargetResolver resolver = new ScrollCaptureTargetResolver(targetQueue);
-        resolver.start(mHandler, RESOLVER_TIMEOUT_MS, mTargetConsumer);
-
-        resolver.waitForResult();
-
-        ScrollCaptureTarget result = mTargetConsumer.getLastValue();
-        assertSame("Expected target1 as the result, due to timeouts of others", target1, result);
-        assertEquals("result has wrong scroll bounds",
-                new Rect(5, 5, 15, 15), result.getScrollBounds());
-        assertEquals("callback1 should have been called",
-                1, callback1.getOnScrollCaptureSearchCount());
-        assertEquals("callback2 should have been called",
-                1, callback2.getOnScrollCaptureSearchCount());
-        assertEquals("callback3 should have been called",
-                1, callback3.getOnScrollCaptureSearchCount());
-    }
-
-    @Test(timeout = TEST_TIMEOUT_MS)
-    public void testWithCallbackMultipleReplies() throws InterruptedException {
-        // Calls response methods 3 times each
-        RepeatingCaptureCallback callback1 = new RepeatingCaptureCallback(3);
-        callback1.setScrollBounds(new Rect(2, 2, 18, 18));
-        ScrollCaptureTarget target1 = createTarget(callback1, new Rect(20, 30, 40, 50),
-                new Point(10, 10), View.SCROLL_CAPTURE_HINT_AUTO);
-
-        FakeScrollCaptureCallback callback2 = new FakeScrollCaptureCallback();
-        callback2.setScrollBounds(new Rect(0, 0, 20, 20));
-        ScrollCaptureTarget target2 = createTarget(callback2, new Rect(20, 30, 40, 50),
-                new Point(10, 10), View.SCROLL_CAPTURE_HINT_AUTO);
-
-        LinkedList<ScrollCaptureTarget> targetQueue = new LinkedList<>();
-        targetQueue.add(target1);
-        targetQueue.add(target2);
-
-        ScrollCaptureTargetResolver resolver = new ScrollCaptureTargetResolver(targetQueue);
-        resolver.start(mHandler, RESOLVER_TIMEOUT_MS, mTargetConsumer);
-
-        resolver.waitForResult();
-
-        ScrollCaptureTarget result = mTargetConsumer.getLastValue();
-        assertSame("Expected target2 as the result, due to hint=INCLUDE", target2, result);
-        assertEquals("result has wrong scroll bounds",
-                new Rect(0, 0, 20, 20), result.getScrollBounds());
-        assertEquals("callback1 should have been called once",
-                1, callback1.getOnScrollCaptureSearchCount());
-        assertEquals("callback2 should have been called once",
-                1, callback2.getOnScrollCaptureSearchCount());
-    }
-
-    private static class TargetConsumer implements Consumer<ScrollCaptureTarget> {
-        volatile ScrollCaptureTarget mResult;
-        int mAcceptCount;
-
-        ScrollCaptureTarget getLastValue() {
-            return mResult;
-        }
-
-        int acceptCount() {
-            return mAcceptCount;
-        }
-
-        @Override
-        public void accept(@Nullable ScrollCaptureTarget t) {
-            mAcceptCount++;
-            mResult = t;
-        }
-    }
-
-    private void setupTargetView(View view, Rect localVisibleRect, int scrollCaptureHint) {
-        view.setScrollCaptureHint(scrollCaptureHint);
-        view.onVisibilityAggregated(true);
-        // Treat any offset as padding, outset localVisibleRect on all sides and use this as
-        // child bounds
-        Rect bounds = new Rect(localVisibleRect);
-        bounds.inset(-bounds.left, -bounds.top, bounds.left, bounds.top);
-        view.layout(bounds.left, bounds.top, bounds.right, bounds.bottom);
-        view.onVisibilityAggregated(true);
-    }
-
-    private ScrollCaptureTarget createTarget(ScrollCaptureCallback callback, Rect localVisibleRect,
-            Point positionInWindow, int scrollCaptureHint) {
-        View mockView = new View(getTargetContext());
-        return createTargetWithView(mockView, callback, localVisibleRect, positionInWindow,
-                scrollCaptureHint);
-    }
-
-    private ScrollCaptureTarget createTargetWithView(View view, ScrollCaptureCallback callback,
-            Rect localVisibleRect, Point positionInWindow, int scrollCaptureHint) {
-        setupTargetView(view, localVisibleRect, scrollCaptureHint);
-        return new ScrollCaptureTarget(view, localVisibleRect, positionInWindow, callback);
-    }
-
-
-    static class FakeRootView extends ViewGroup implements ViewParent {
-        FakeRootView(Context context, int l, int t, int r, int b) {
-            super(context);
-            layout(l, t, r, b);
-        }
-
-        @Override
-        protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        }
-    }
-
-    static class FakeScrollCaptureCallback implements ScrollCaptureCallback {
-        private Rect mScrollBounds;
-        private long mDelayMillis;
-        private int mOnScrollCaptureSearchCount;
-
-        public int getOnScrollCaptureSearchCount() {
-            return mOnScrollCaptureSearchCount;
-        }
-
-        @Override
-        public void onScrollCaptureSearch(Consumer<Rect> onReady) {
-            mOnScrollCaptureSearchCount++;
-            run(() -> {
-                Rect b = getScrollBounds();
-                onReady.accept(b);
-            });
-        }
-
-        @Override
-        public void onScrollCaptureStart(ScrollCaptureSession session, Runnable onReady) {
-            run(onReady);
-        }
-
-        @Override
-        public void onScrollCaptureImageRequest(ScrollCaptureSession session, Rect captureArea) {
-            run(() -> session.notifyBufferSent(0, captureArea));
-        }
-
-        @Override
-        public void onScrollCaptureEnd(Runnable onReady) {
-            run(onReady);
-        }
-
-        public void setScrollBounds(@Nullable Rect scrollBounds) {
-            mScrollBounds = scrollBounds;
-        }
-
-        public void setDelay(long delayMillis) {
-            mDelayMillis = delayMillis;
-        }
-
-        protected Rect getScrollBounds() {
-            return mScrollBounds;
-        }
-
-        protected void run(Runnable r) {
-            delay();
-            r.run();
-        }
-
-        protected void delay() {
-            if (mDelayMillis > 0) {
-                try {
-                    Thread.sleep(mDelayMillis);
-                } catch (InterruptedException e) {
-                    // Ignore
-                }
-            }
-        }
-    }
-
-    static class RepeatingCaptureCallback extends FakeScrollCaptureCallback {
-        private int mRepeatCount;
-
-        RepeatingCaptureCallback(int repeatCount) {
-            mRepeatCount = repeatCount;
-        }
-
-        protected void run(Runnable r) {
-            delay();
-            for (int i = 0; i < mRepeatCount; i++) {
-                r.run();
-            }
-        }
-    }
-
-    /** Response to async calls on an arbitrary background thread */
-    static class BackgroundTestCallback extends FakeScrollCaptureCallback {
-        static int sCount = 0;
-        private void runOnBackgroundThread(Runnable r) {
-            final Runnable target = () -> {
-                delay();
-                r.run();
-            };
-            Thread t = new Thread(target);
-            synchronized (BackgroundTestCallback.this) {
-                sCount++;
-            }
-            t.setName("Background-Thread-" + sCount);
-            t.start();
-        }
-
-        @Override
-        protected void run(Runnable r) {
-            runOnBackgroundThread(r);
-        }
-    }
-}
diff --git a/core/tests/coretests/src/android/view/SoundEffectConstantsTest.java b/core/tests/coretests/src/android/view/SoundEffectConstantsTest.java
new file mode 100644
index 0000000..45ffb122
--- /dev/null
+++ b/core/tests/coretests/src/android/view/SoundEffectConstantsTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link SoundEffectConstants}
+ *
+ * Build/Install/Run:
+ *  atest FrameworksCoreTests:SoundEffectConstantsTest
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SoundEffectConstantsTest {
+
+    @Test
+    public void testIsNavigationRepeat() {
+        assertTrue(SoundEffectConstants.isNavigationRepeat(
+                SoundEffectConstants.NAVIGATION_REPEAT_RIGHT));
+        assertTrue(SoundEffectConstants.isNavigationRepeat(
+                SoundEffectConstants.NAVIGATION_REPEAT_LEFT));
+        assertTrue(
+                SoundEffectConstants.isNavigationRepeat(SoundEffectConstants.NAVIGATION_REPEAT_UP));
+        assertTrue(SoundEffectConstants.isNavigationRepeat(
+                SoundEffectConstants.NAVIGATION_REPEAT_DOWN));
+        assertFalse(SoundEffectConstants.isNavigationRepeat(SoundEffectConstants.NAVIGATION_RIGHT));
+        assertFalse(SoundEffectConstants.isNavigationRepeat(SoundEffectConstants.NAVIGATION_LEFT));
+        assertFalse(SoundEffectConstants.isNavigationRepeat(SoundEffectConstants.NAVIGATION_UP));
+        assertFalse(SoundEffectConstants.isNavigationRepeat(SoundEffectConstants.NAVIGATION_DOWN));
+        assertFalse(SoundEffectConstants.isNavigationRepeat(-1));
+    }
+}
diff --git a/core/tests/coretests/src/android/view/SurfaceControlFpsListenerTest.java b/core/tests/coretests/src/android/view/SurfaceControlFpsListenerTest.java
new file mode 100644
index 0000000..36104cf
--- /dev/null
+++ b/core/tests/coretests/src/android/view/SurfaceControlFpsListenerTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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.view;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class SurfaceControlFpsListenerTest {
+
+    @Test
+    public void registersAndUnregisters() {
+
+        SurfaceControlFpsListener listener = new SurfaceControlFpsListener() {
+            @Override
+            public void onFpsReported(float fps) {
+                // Ignore
+            }
+        };
+
+        listener.register(new SurfaceControl());
+
+        listener.unregister();
+    }
+}
diff --git a/core/tests/coretests/src/android/view/TestScrollCaptureCallback.java b/core/tests/coretests/src/android/view/TestScrollCaptureCallback.java
new file mode 100644
index 0000000..1520c6e
--- /dev/null
+++ b/core/tests/coretests/src/android/view/TestScrollCaptureCallback.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import static org.junit.Assert.*;
+
+import android.graphics.Rect;
+import android.os.CancellationSignal;
+
+import androidx.annotation.NonNull;
+
+import java.util.function.Consumer;
+
+class TestScrollCaptureCallback implements ScrollCaptureCallback {
+    private Consumer<Rect> mSearchConsumer;
+    private Runnable mStartOnReady;
+    private Consumer<Rect> mImageOnComplete;
+    private Runnable mOnEndReady;
+    private volatile int mModCount;
+
+    @Override
+    public void onScrollCaptureSearch(@NonNull CancellationSignal signal,
+            @NonNull Consumer<Rect> onReady) {
+        mSearchConsumer = onReady;
+        mModCount++;
+    }
+
+    @Override
+    public void onScrollCaptureStart(@NonNull ScrollCaptureSession session,
+            @NonNull CancellationSignal signal, @NonNull Runnable onReady) {
+        mStartOnReady = onReady;
+        mModCount++;
+    }
+
+    @Override
+    public void onScrollCaptureImageRequest(@NonNull ScrollCaptureSession session,
+            @NonNull CancellationSignal signal, @NonNull Rect captureArea,
+            @NonNull Consumer<Rect> onComplete) {
+        mImageOnComplete = onComplete;
+        mModCount++;
+    }
+
+    @Override
+    public void onScrollCaptureEnd(@NonNull Runnable onReady) {
+        mOnEndReady = onReady;
+    }
+
+    void completeSearchRequest(Rect scrollBounds) {
+        assertNotNull("Did not receive search request", mSearchConsumer);
+        mSearchConsumer.accept(scrollBounds);
+        mModCount++;
+    }
+
+    void verifyZeroInteractions() {
+        assertEquals("Expected zero interactions", 0, mModCount);
+    }
+
+    void completeStartRequest() {
+        assertNotNull("Did not receive start request", mStartOnReady);
+        mStartOnReady.run();
+    }
+
+    void completeImageRequest(Rect captured) {
+        assertNotNull("Did not receive image request", mImageOnComplete);
+        mImageOnComplete.accept(captured);
+    }
+
+    void completeEndRequest() {
+        assertNotNull("Did not receive end request", mOnEndReady);
+        mOnEndReady.run();
+    }
+}
diff --git a/core/tests/coretests/src/android/view/ViewGroupScrollCaptureTest.java b/core/tests/coretests/src/android/view/ViewGroupScrollCaptureTest.java
index 3af0533..41cd4c5 100644
--- a/core/tests/coretests/src/android/view/ViewGroupScrollCaptureTest.java
+++ b/core/tests/coretests/src/android/view/ViewGroupScrollCaptureTest.java
@@ -19,7 +19,9 @@
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.testng.AssertJUnit.assertSame;
 
@@ -27,19 +29,20 @@
 import android.content.Context;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.os.CancellationSignal;
 import android.platform.test.annotations.Presubmit;
 
+import androidx.annotation.NonNull;
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 
-import java.util.LinkedList;
-import java.util.Queue;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 /**
  * Exercises Scroll Capture search in {@link ViewGroup}.
@@ -50,10 +53,7 @@
 @RunWith(MockitoJUnitRunner.class)
 public class ViewGroupScrollCaptureTest {
 
-    @Mock
-    ScrollCaptureCallback mMockCallback;
-    @Mock
-    ScrollCaptureCallback mMockCallback2;
+    private static final Executor DIRECT_EXECUTOR = Runnable::run;
 
     /** Make sure the hint flags are saved and loaded correctly. */
     @Test
@@ -103,25 +103,24 @@
     public void testDispatchScrollCaptureSearch_noCallback_hintAuto() throws Exception {
         final Context context = getInstrumentation().getContext();
         final MockViewGroup viewGroup = new MockViewGroup(context, 0, 0, 200, 200);
+        TestScrollCaptureCallback callback = new TestScrollCaptureCallback();
 
         // When system internal scroll capture is requested, this callback is returned.
-        viewGroup.setScrollCaptureCallbackInternalForTest(mMockCallback);
+        viewGroup.setScrollCaptureCallbackInternalForTest(callback);
 
         Rect localVisibleRect = new Rect(0, 0, 200, 200);
         Point windowOffset = new Point();
-        LinkedList<ScrollCaptureTarget> targetList = new LinkedList<>();
+        ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(DIRECT_EXECUTOR);
 
         // Dispatch
-        viewGroup.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, targetList);
-
-        // Verify the system checked for fallback support
-        viewGroup.assertDispatchScrollCaptureCount(1);
-        viewGroup.assertLastDispatchScrollCaptureArgs(localVisibleRect, windowOffset);
+        viewGroup.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, results::addTarget);
+        callback.completeSearchRequest(new Rect(1, 2, 3, 4));
+        assertTrue(results.isComplete());
 
         // Verify the target is as expected.
-        assertEquals(1, targetList.size());
-        ScrollCaptureTarget target = targetList.get(0);
-        assertSame("Target has the wrong callback", mMockCallback, target.getCallback());
+        ScrollCaptureTarget target = results.getTopResult();
+        assertNotNull("Target not found", target);
+        assertSame("Target has the wrong callback", callback, target.getCallback());
         assertSame("Target has the wrong View", viewGroup, target.getContainingView());
         assertEquals("Target hint is incorrect", View.SCROLL_CAPTURE_HINT_AUTO,
                 target.getContainingView().getScrollCaptureHint());
@@ -139,18 +138,22 @@
         final MockViewGroup viewGroup =
                 new MockViewGroup(context, 0, 0, 200, 200, View.SCROLL_CAPTURE_HINT_EXCLUDE);
 
+        TestScrollCaptureCallback callback = new TestScrollCaptureCallback();
+
         // When system internal scroll capture is requested, this callback is returned.
-        viewGroup.setScrollCaptureCallbackInternalForTest(mMockCallback);
+        viewGroup.setScrollCaptureCallbackInternalForTest(callback);
 
         Rect localVisibleRect = new Rect(0, 0, 200, 200);
         Point windowOffset = new Point();
-        LinkedList<ScrollCaptureTarget> targetList = new LinkedList<>();
+        ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(DIRECT_EXECUTOR);
+        assertTrue(results.isComplete());
 
         // Dispatch
-        viewGroup.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, targetList);
+        viewGroup.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, results::addTarget);
+        callback.verifyZeroInteractions();
 
         // Verify the results.
-        assertEquals("Target list size should be zero.", 0, targetList.size());
+        assertTrue("Results should be empty.", results.isEmpty());
     }
 
     /**
@@ -164,27 +167,34 @@
         final Context context = getInstrumentation().getContext();
         MockViewGroup viewGroup = new MockViewGroup(context, 0, 0, 200, 200);
 
+        TestScrollCaptureCallback callback = new TestScrollCaptureCallback();
+        TestScrollCaptureCallback callback2 = new TestScrollCaptureCallback();
+
         // With an already provided scroll capture callback
-        viewGroup.setScrollCaptureCallback(mMockCallback);
+        viewGroup.setScrollCaptureCallback(callback);
 
         // When system internal scroll capture is requested, this callback is returned.
-        viewGroup.setScrollCaptureCallbackInternalForTest(mMockCallback);
+        viewGroup.setScrollCaptureCallbackInternalForTest(callback2);
 
         Rect localVisibleRect = new Rect(0, 0, 200, 200);
         Point windowOffset = new Point();
-        LinkedList<ScrollCaptureTarget> targetList = new LinkedList<>();
+        ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(DIRECT_EXECUTOR);
 
         // Dispatch to the ViewGroup
-        viewGroup.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, targetList);
-
-        // Confirm that framework support was not requested,
-        // because this view already had a callback set.
-        viewGroup.assertCreateScrollCaptureCallbackInternalCount(0);
+        viewGroup.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, results::addTarget);
+        callback.completeSearchRequest(new Rect(1, 2, 3, 4));
 
         // Verify the target is as expected.
-        assertEquals(1, targetList.size());
-        ScrollCaptureTarget target = targetList.get(0);
-        assertSame("Target has the wrong callback", mMockCallback, target.getCallback());
+        assertFalse(results.isEmpty());
+        assertTrue(results.isComplete());
+
+        // internal framework callback was not requested
+        callback2.verifyZeroInteractions();
+
+        ScrollCaptureTarget target = results.getTopResult();
+
+        assertNotNull("Target not found", target);
+        assertSame("Target has the wrong callback", callback, target.getCallback());
         assertSame("Target has the wrong View", viewGroup, target.getContainingView());
         assertEquals("Target hint is incorrect", View.SCROLL_CAPTURE_HINT_AUTO,
                 target.getContainingView().getScrollCaptureHint());
@@ -201,22 +211,22 @@
         final Context context = getInstrumentation().getContext();
         MockViewGroup viewGroup =
                 new MockViewGroup(context, 0, 0, 200, 200, View.SCROLL_CAPTURE_HINT_EXCLUDE);
+
+        TestScrollCaptureCallback callback = new TestScrollCaptureCallback();
+
         // With an already provided scroll capture callback
-        viewGroup.setScrollCaptureCallback(mMockCallback);
+        viewGroup.setScrollCaptureCallback(callback);
 
         Rect localVisibleRect = new Rect(0, 0, 200, 200);
         Point windowOffset = new Point();
-        LinkedList<ScrollCaptureTarget> targetList = new LinkedList<>();
+        ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(DIRECT_EXECUTOR);
 
         // Dispatch to the ViewGroup itself
-        viewGroup.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, targetList);
-
-        // Confirm that framework support was not requested, because this view is excluded.
-        // (And because this view has a callback set.)
-        viewGroup.assertCreateScrollCaptureCallbackInternalCount(0);
+        viewGroup.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, results::addTarget);
+        callback.verifyZeroInteractions();
 
         // Has callback, but hint=excluded, so excluded.
-        assertTrue(targetList.isEmpty());
+        assertNull(results.getTopResult());
     }
 
     /**
@@ -252,37 +262,43 @@
         // |               |          |
         // +---------------+----------+ (200,200)
 
-        // View 1 is clipped and not visible.
+        // View 1 is fully clipped and not visible.
         final MockView view1 = new MockView(context, 0, 0, 200, 25);
         viewGroup.addView(view1);
 
-        // View 2 is partially visible.
+        // View 2 is partially visible. (75x75)
         final MockView view2 = new MockView(context, 0, 25, 150, 100);
         viewGroup.addView(view2);
 
-        // View 3 is partially visible.
+        TestScrollCaptureCallback callback1 = new TestScrollCaptureCallback();
+
+        // View 3 is partially visible (175x50)
         // Pretend View3 can scroll by having framework provide fallback support
         final MockView view3 = new MockView(context, 0, 100, 200, 200);
         // When system internal scroll capture is requested for this view, return this callback.
-        view3.setScrollCaptureCallbackInternalForTest(mMockCallback);
+        view3.setScrollCaptureCallbackInternalForTest(callback1);
         viewGroup.addView(view3);
 
         // View 4 is invisible and should be ignored.
         final MockView view4 = new MockView(context, 150, 25, 200, 100, View.INVISIBLE);
         viewGroup.addView(view4);
 
-        // View 4 is invisible and should be ignored.
+        TestScrollCaptureCallback callback2 = new TestScrollCaptureCallback();
+
+        // View 5 is partially visible and explicitly included via flag. (25x50)
         final MockView view5 = new MockView(context, 150, 100, 200, 200);
-        // When system internal scroll capture is requested for this view, return this callback.
-        view5.setScrollCaptureCallback(mMockCallback2);
+        view5.setScrollCaptureCallback(callback2);
         view5.setScrollCaptureHint(View.SCROLL_CAPTURE_HINT_INCLUDE);
         viewGroup.addView(view5);
 
         // Where targets are added
-        final LinkedList<ScrollCaptureTarget> targetList = new LinkedList<>();
+        final ScrollCaptureSearchResults results = new ScrollCaptureSearchResults(DIRECT_EXECUTOR);
 
         // Dispatch to the ViewGroup
-        viewGroup.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, targetList);
+        viewGroup.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, results::addTarget);
+        callback1.completeSearchRequest(new Rect(0, 0, 200, 100));
+        callback2.completeSearchRequest(new Rect(0, 0, 50, 100));
+        assertTrue(results.isComplete());
 
         // View 1 is entirely clipped by the parent and not visible, dispatch
         // skips this view entirely.
@@ -317,18 +333,14 @@
         view5.assertCreateScrollCaptureCallbackInternalCount(0);
 
         // 2 views should have been returned, view3 & view5
-        assertEquals(2, targetList.size());
+        assertFalse(results.isEmpty());
+        assertTrue(results.isComplete());
 
-        ScrollCaptureTarget target = targetList.get(0);
-        assertSame("First target has the wrong View", view3, target.getContainingView());
-        assertSame("First target has the wrong callback", mMockCallback, target.getCallback());
-        assertEquals("First target hint is incorrect", View.SCROLL_CAPTURE_HINT_AUTO,
-                target.getContainingView().getScrollCaptureHint());
-
-        target = targetList.get(1);
-        assertSame("Second target has the wrong View", view5, target.getContainingView());
-        assertSame("Second target has the wrong callback", mMockCallback2, target.getCallback());
-        assertEquals("Second target hint is incorrect", View.SCROLL_CAPTURE_HINT_INCLUDE,
+        ScrollCaptureTarget target = results.getTopResult();
+        assertNotNull("Target not found", target);
+        assertSame("Result is the wrong View", view5, target.getContainingView());
+        assertSame("Result is the wrong callback", callback2, target.getCallback());
+        assertEquals("First target hint is incorrect", View.SCROLL_CAPTURE_HINT_INCLUDE,
                 target.getContainingView().getScrollCaptureHint());
     }
 
@@ -371,7 +383,7 @@
         }
 
         void assertCreateScrollCaptureCallbackInternalCount(int count) {
-            assertEquals("Unexpected number of calls to createScrollCaptureCallackInternal",
+            assertEquals("Unexpected number of calls to createScrollCaptureCallbackInternal",
                     count, mCreateScrollCaptureCallbackInternalCount);
         }
 
@@ -385,11 +397,11 @@
 
         @Override
         public void dispatchScrollCaptureSearch(Rect localVisibleRect, Point windowOffset,
-                Queue<ScrollCaptureTarget> targets) {
+                Consumer<ScrollCaptureTarget> results) {
             mDispatchScrollCaptureSearchNumCalls++;
             mDispatchScrollCaptureSearchLastLocalVisibleRect = new Rect(localVisibleRect);
             mDispatchScrollCaptureSearchLastWindowOffset = new Point(windowOffset);
-            super.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, targets);
+            super.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, results);
         }
 
         @Override
@@ -401,13 +413,31 @@
         }
     }
 
+    static class CallbackStub implements ScrollCaptureCallback {
+
+        @Override
+        public void onScrollCaptureSearch(@NonNull CancellationSignal signal,
+                @NonNull Consumer<Rect> onReady) {
+        }
+
+        @Override
+        public void onScrollCaptureStart(@NonNull ScrollCaptureSession session,
+                @NonNull CancellationSignal signal, @NonNull Runnable onReady) {
+        }
+
+        @Override
+        public void onScrollCaptureImageRequest(@NonNull ScrollCaptureSession session,
+                @NonNull CancellationSignal signal, @NonNull Rect captureArea,
+                Consumer<Rect> onComplete) {
+        }
+
+        @Override
+        public void onScrollCaptureEnd(@NonNull Runnable onReady) {
+        }
+    };
+
     public static final class MockViewGroup extends ViewGroup {
         private ScrollCaptureCallback mInternalCallback;
-        private int mDispatchScrollCaptureSearchNumCalls;
-        private Rect mDispatchScrollCaptureSearchLastLocalVisibleRect;
-        private Point mDispatchScrollCaptureSearchLastWindowOffset;
-        private int mCreateScrollCaptureCallbackInternalCount;
-
 
         MockViewGroup(Context context) {
             this(context, /* left */ 0, /* top */0, /* right */ 0, /* bottom */0);
@@ -428,16 +458,10 @@
             mInternalCallback = internal;
         }
 
-        void assertDispatchScrollCaptureSearchCount(int count) {
-            assertEquals("Unexpected number of calls to dispatchScrollCaptureSearch",
-                    count, mDispatchScrollCaptureSearchNumCalls);
-        }
-
         @Override
         @Nullable
         public ScrollCaptureCallback createScrollCaptureCallbackInternal(Rect localVisibleRect,
                 Point offsetInWindow) {
-            mCreateScrollCaptureCallbackInternalCount++;
             return mInternalCallback;
         }
 
@@ -445,36 +469,5 @@
         protected void onLayout(boolean changed, int l, int t, int r, int b) {
             // We don't layout this view.
         }
-
-        void assertDispatchScrollCaptureCount(int count) {
-            assertEquals(count, mDispatchScrollCaptureSearchNumCalls);
-        }
-
-        void assertLastDispatchScrollCaptureArgs(Rect localVisibleRect, Point windowOffset) {
-            assertEquals("arg localVisibleRect to dispatchScrollCaptureCallback was incorrect.",
-                    localVisibleRect, mDispatchScrollCaptureSearchLastLocalVisibleRect);
-            assertEquals("arg windowOffset to dispatchScrollCaptureCallback was incorrect.",
-                    windowOffset, mDispatchScrollCaptureSearchLastWindowOffset);
-        }
-        void assertCreateScrollCaptureCallbackInternalCount(int count) {
-            assertEquals("Unexpected number of calls to createScrollCaptureCallackInternal",
-                    count, mCreateScrollCaptureCallbackInternalCount);
-        }
-
-        void reset() {
-            mDispatchScrollCaptureSearchNumCalls = 0;
-            mDispatchScrollCaptureSearchLastWindowOffset = null;
-            mDispatchScrollCaptureSearchLastLocalVisibleRect = null;
-            mCreateScrollCaptureCallbackInternalCount = 0;
-        }
-
-        @Override
-        public void dispatchScrollCaptureSearch(Rect localVisibleRect, Point windowOffset,
-                Queue<ScrollCaptureTarget> targets) {
-            mDispatchScrollCaptureSearchNumCalls++;
-            mDispatchScrollCaptureSearchLastLocalVisibleRect = new Rect(localVisibleRect);
-            mDispatchScrollCaptureSearchLastWindowOffset = new Point(windowOffset);
-            super.dispatchScrollCaptureSearch(localVisibleRect, windowOffset, targets);
-        }
     }
 }
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index c67174f..7746bc2 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -207,7 +207,7 @@
         final CountDownLatch latch = new CountDownLatch(1);
         mViewRootImpl.handleScrollCaptureRequest(new IScrollCaptureCallbacks.Default() {
             @Override
-            public void onUnavailable() {
+            public void onScrollCaptureResponse(ScrollCaptureResponse response) {
                 latch.countDown();
             }
         });
@@ -220,6 +220,37 @@
     }
 
     /**
+     * Ensure scroll capture request handles a ViewRootImpl with no view tree.
+     */
+    @Test
+    public void requestScrollCapture_timeout() {
+        final View view = new View(mContext);
+        view.setScrollCaptureCallback(new TestScrollCaptureCallback()); // Does nothing
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            WindowManager.LayoutParams wmlp =
+                    new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);
+            // Set a fake token to bypass 'is your activity running' check
+            wmlp.token = new Binder();
+            view.setLayoutParams(wmlp);
+            mViewRootImpl.setView(view, wmlp, null);
+        });
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        mViewRootImpl.setScrollCaptureRequestTimeout(100);
+        mViewRootImpl.handleScrollCaptureRequest(new IScrollCaptureCallbacks.Default() {
+            @Override
+            public void onScrollCaptureResponse(ScrollCaptureResponse response) {
+                latch.countDown();
+            }
+        });
+        try {
+            if (!latch.await(2500, TimeUnit.MILLISECONDS)) {
+                fail("requestScrollCapture timeout did not occur");
+            }
+        } catch (InterruptedException e) { /* ignore */ }
+    }
+
+    /**
      * When window doesn't have focus, keys should be dropped.
      */
     @Test
diff --git a/core/tests/coretests/src/android/view/accessibility/OWNERS b/core/tests/coretests/src/android/view/accessibility/OWNERS
new file mode 100644
index 0000000..b74281e
--- /dev/null
+++ b/core/tests/coretests/src/android/view/accessibility/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/accessibility/OWNERS
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureContextTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureContextTest.java
index 4680a64..ddb6729 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureContextTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureContextTest.java
@@ -17,14 +17,17 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.app.assist.ActivityId;
 import android.content.ComponentName;
+import android.os.Binder;
+import android.os.IBinder;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
 /**
- * Unit test for {@link ContentCaptureEvent}.
+ * Unit test for {@link ContentCaptureContext}.
  *
  * <p>To run it:
  * {@code atest FrameworksCoreTests:android.view.contentcapture.ContentCaptureContextTest}
@@ -35,13 +38,17 @@
     @Test
     public void testConstructorAdditionalFlags() {
         final ComponentName componentName = new ComponentName("component", "name");
+        final IBinder token = new Binder();
         final ContentCaptureContext ctx = new ContentCaptureContext(/* clientContext= */ null,
-                componentName, /* taskId= */ 666, /* displayId= */ 42, /* flags= */ 1);
+                new ActivityId(/* taskId= */ 666, token), componentName, /* displayId= */
+                42, /* flags= */ 1);
         final ContentCaptureContext newCtx = new ContentCaptureContext(ctx, /* extraFlags= */ 2);
         assertThat(newCtx.getFlags()).isEqualTo(3);
-
         assertThat(newCtx.getActivityComponent()).isEqualTo(componentName);
-        assertThat(newCtx.getTaskId()).isEqualTo(666);
+        ActivityId activityId = newCtx.getActivityId();
+        assertThat(activityId).isNotNull();
+        assertThat(activityId.getTaskId()).isEqualTo(666);
+        assertThat(activityId.getToken()).isEqualTo(token);
         assertThat(newCtx.getDisplayId()).isEqualTo(42);
         assertThat(newCtx.getExtras()).isNull();
         assertThat(newCtx.getLocusId()).isNull();
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
index 9cac7e7..ff728d6 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
@@ -77,6 +77,7 @@
  * bit FrameworksCoreTests:com.android.internal.os.BatteryStatsCpuTimesTest
  */
 @SmallTest
+@SkipPresubmit("b/180015146")
 @RunWith(AndroidJUnit4.class)
 public class BatteryStatsCpuTimesTest {
     @Mock
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryIteratorTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryIteratorTest.java
new file mode 100644
index 0000000..263daf0
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryIteratorTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.BatteryManager;
+import android.os.BatteryStats;
+import android.os.Process;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class BatteryStatsHistoryIteratorTest {
+    private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
+
+    @Rule
+    public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule();
+
+    @Test
+    public void testIterator() {
+        MockBatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
+        batteryStats.setRecordAllHistoryLocked(true);
+        batteryStats.forceRecordAllHistory();
+
+        mStatsRule.setTime(1000, 1000);
+        batteryStats.setNoAutoReset(true);
+
+        batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,
+                /* plugType */ 0, 90, 72, 3700, 3_600_000, 4_000_000, 0, 1_000_000,
+                1_000_000, 1_000_000);
+        batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,
+                /* plugType */ 0, 80, 72, 3700, 2_400_000, 4_000_000, 0, 2_000_000,
+                2_000_000, 2_000_000);
+
+        batteryStats.noteAlarmStartLocked("foo", null, APP_UID, 3_000_000, 2_000_000);
+        batteryStats.noteAlarmFinishLocked("foo", null, APP_UID, 3_001_000, 2_001_000);
+
+        final BatteryStatsHistoryIterator iterator =
+                batteryStats.createBatteryStatsHistoryIterator();
+
+        BatteryStats.HistoryItem item = new BatteryStats.HistoryItem();
+
+        assertThat(iterator.next(item)).isTrue();
+        assertHistoryItem(item,
+                BatteryStats.HistoryItem.CMD_RESET, BatteryStats.HistoryItem.EVENT_NONE,
+                null, 0, 3_600_000, 90, 1_000_000);
+
+        assertThat(iterator.next(item)).isTrue();
+        assertHistoryItem(item,
+                BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_NONE,
+                null, 0, 3_600_000, 90, 1_000_000);
+
+        assertThat(iterator.next(item)).isTrue();
+        assertHistoryItem(item,
+                BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_NONE,
+                null, 0, 2_400_000, 80, 2_000_000);
+
+        assertThat(iterator.next(item)).isTrue();
+        assertHistoryItem(item,
+                BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_NONE,
+                null, 0, 2_400_000, 80, 2_000_000);
+
+        assertThat(iterator.next(item)).isTrue();
+        assertHistoryItem(item,
+                BatteryStats.HistoryItem.CMD_UPDATE,
+                BatteryStats.HistoryItem.EVENT_ALARM | BatteryStats.HistoryItem.EVENT_FLAG_START,
+                "foo", APP_UID, 2_400_000, 80, 3_000_000);
+
+        assertThat(iterator.next(item)).isTrue();
+        assertHistoryItem(item,
+                BatteryStats.HistoryItem.CMD_UPDATE,
+                BatteryStats.HistoryItem.EVENT_ALARM | BatteryStats.HistoryItem.EVENT_FLAG_FINISH,
+                "foo", APP_UID, 2_400_000, 80, 3_001_000);
+
+        assertThat(iterator.next(item)).isFalse();
+    }
+
+    private void assertHistoryItem(BatteryStats.HistoryItem item, int command, int eventCode,
+            String tag, int uid, int batteryChargeUah, int batteryLevel,
+            long elapsedTimeMs) {
+        assertThat(item.cmd).isEqualTo(command);
+        assertThat(item.eventCode).isEqualTo(eventCode);
+        if (tag == null) {
+            assertThat(item.eventTag).isNull();
+        } else {
+            assertThat(item.eventTag.string).isEqualTo(tag);
+            assertThat(item.eventTag.uid).isEqualTo(uid);
+        }
+        assertThat(item.batteryChargeUah).isEqualTo(batteryChargeUah);
+        assertThat(item.batteryLevel).isEqualTo(batteryLevel);
+
+        assertThat(item.time).isEqualTo(elapsedTimeMs);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
index 4b37dd2..24baa93 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
@@ -73,6 +73,7 @@
     }
 
     @Test
+    @SkipPresubmit("b/180015146")
     public void testUpdateProcStateCpuTimes() {
         mBatteryStatsImpl.setOnBatteryInternal(true);
         mBatteryStatsImpl.updateTimeBasesLocked(false, Display.STATE_ON, 0, 0);
@@ -230,6 +231,7 @@
     }
 
     @Test
+    @SkipPresubmit("b/180015146")
     public void testCopyFromAllUidsCpuTimes() {
         mBatteryStatsImpl.setOnBatteryInternal(false);
         mBatteryStatsImpl.updateTimeBasesLocked(false, Display.STATE_ON, 0, 0);
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
index 6652c64..931611e 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -295,6 +295,7 @@
     }
 
     @SmallTest
+    @SkipPresubmit("b/180015146")
     public void testAlarmStartAndFinishLocked() throws Exception {
         final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
         MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
@@ -332,6 +333,7 @@
     }
 
     @SmallTest
+    @SkipPresubmit("b/180015146")
     public void testAlarmStartAndFinishLocked_workSource() throws Exception {
         final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
         MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
index 3b27f18..dd814e6 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
@@ -56,6 +56,7 @@
     }
 
     @SmallTest
+    @SkipPresubmit("b/180015146")
     public void testEndSampleAndContinueWhenTimeOrCountDecreases() throws Exception {
         final MockClocks clocks = new MockClocks();
         final BatteryStatsImpl.TimeBase timeBase = Mockito.mock(BatteryStatsImpl.TimeBase.class);
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index b819d9e..74c37ada 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -30,6 +30,7 @@
         BatteryStatsDualTimerTest.class,
         BatteryStatsDurationTimerTest.class,
         BatteryStatsHelperTest.class,
+        BatteryStatsHistoryIteratorTest.class,
         BatteryStatsHistoryTest.class,
         BatteryStatsImplTest.class,
         BatteryStatsNoteTest.class,
@@ -40,6 +41,7 @@
         BatteryStatsTimeBaseTest.class,
         BatteryStatsTimerTest.class,
         BatteryStatsUidTest.class,
+        BatteryUsageStatsProviderTest.class,
         BatteryUsageStatsTest.class,
         BatteryStatsUserLifecycleTests.class,
         BluetoothPowerCalculatorTest.class,
@@ -71,9 +73,9 @@
         UserPowerCalculatorTest.class,
         VideoPowerCalculatorTest.class,
         WakelockPowerCalculatorTest.class,
+        WifiPowerCalculatorTest.class,
 
         com.android.internal.power.MeasuredEnergyStatsTest.class
     })
 public class BatteryStatsTests {
-}
-
+}
\ No newline at end of file
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsUserLifecycleTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUserLifecycleTests.java
index e7a1bca..e90bcb7 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsUserLifecycleTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUserLifecycleTests.java
@@ -78,6 +78,7 @@
     }
 
     @Test
+    @SkipPresubmit("b/180015146")
     public void testNoCpuDataForRemovedUser() throws Exception {
         mIam.startUserInBackground(mTestUserId);
         waitUntilTrue("No uids for started user " + mTestUserId,
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
new file mode 100644
index 0000000..0f59143
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
@@ -0,0 +1,161 @@
+/*
+ * 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.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.os.BatteryManager;
+import android.os.BatteryStats;
+import android.os.BatteryUsageStats;
+import android.os.BatteryUsageStatsQuery;
+import android.os.Parcel;
+import android.os.Process;
+import android.os.UidBatteryConsumer;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BatteryUsageStatsProviderTest {
+    private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
+    private static final long MINUTE_IN_MS = 60 * 1000;
+
+    @Rule
+    public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule();
+
+    @Test
+    public void test_getBatteryUsageStats() {
+        BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
+
+        batteryStats.noteActivityResumedLocked(APP_UID,
+                10 * MINUTE_IN_MS, 10 * MINUTE_IN_MS);
+        batteryStats.noteUidProcessStateLocked(APP_UID, ActivityManager.PROCESS_STATE_TOP,
+                10 * MINUTE_IN_MS, 10 * MINUTE_IN_MS);
+        batteryStats.noteActivityPausedLocked(APP_UID,
+                30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
+        batteryStats.noteUidProcessStateLocked(APP_UID, ActivityManager.PROCESS_STATE_SERVICE,
+                30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
+        batteryStats.noteUidProcessStateLocked(APP_UID, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
+                40 * MINUTE_IN_MS, 40 * MINUTE_IN_MS);
+
+        Context context = InstrumentationRegistry.getContext();
+        BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(context, batteryStats);
+
+        final BatteryUsageStats batteryUsageStats =
+                provider.getBatteryUsageStats(BatteryUsageStatsQuery.DEFAULT);
+
+        final List<UidBatteryConsumer> uidBatteryConsumers =
+                batteryUsageStats.getUidBatteryConsumers();
+        final UidBatteryConsumer uidBatteryConsumer = uidBatteryConsumers.get(0);
+        assertThat(uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND))
+                .isEqualTo(20 * MINUTE_IN_MS);
+        assertThat(uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND))
+                .isEqualTo(10 * MINUTE_IN_MS);
+    }
+
+    @Test
+    public void testWriteAndReadHistory() {
+        MockBatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
+        batteryStats.setRecordAllHistoryLocked(true);
+        batteryStats.forceRecordAllHistory();
+
+        batteryStats.setNoAutoReset(true);
+
+        batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,
+                /* plugType */ 0, 90, 72, 3700, 3_600_000, 4_000_000, 0, 1_000_000,
+                1_000_000, 1_000_000);
+
+        batteryStats.noteAlarmStartLocked("foo", null, APP_UID, 3_000_000, 2_000_000);
+        batteryStats.noteAlarmFinishLocked("foo", null, APP_UID, 3_001_000, 2_001_000);
+
+        Context context = InstrumentationRegistry.getContext();
+        BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(context, batteryStats);
+
+        final BatteryUsageStats batteryUsageStats =
+                provider.getBatteryUsageStats(
+                        new BatteryUsageStatsQuery.Builder().includeBatteryHistory().build());
+
+        Parcel in = Parcel.obtain();
+        batteryUsageStats.writeToParcel(in, 0);
+        final byte[] bytes = in.marshall();
+
+        Parcel out = Parcel.obtain();
+        out.unmarshall(bytes, 0, bytes.length);
+        out.setDataPosition(0);
+
+        BatteryUsageStats unparceled = BatteryUsageStats.CREATOR.createFromParcel(out);
+
+        final BatteryStatsHistoryIterator iterator =
+                unparceled.iterateBatteryStatsHistory();
+        BatteryStats.HistoryItem item = new BatteryStats.HistoryItem();
+
+        assertThat(iterator.next(item)).isTrue();
+        assertHistoryItem(item,
+                BatteryStats.HistoryItem.CMD_RESET, BatteryStats.HistoryItem.EVENT_NONE,
+                null, 0, 3_600_000, 90, 1_000_000);
+
+        assertThat(iterator.next(item)).isTrue();
+        assertHistoryItem(item,
+                BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_NONE,
+                null, 0, 3_600_000, 90, 1_000_000);
+
+        assertThat(iterator.next(item)).isTrue();
+        assertHistoryItem(item,
+                BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_NONE,
+                null, 0, 3_600_000, 90, 2_000_000);
+
+        assertThat(iterator.next(item)).isTrue();
+        assertHistoryItem(item,
+                BatteryStats.HistoryItem.CMD_UPDATE,
+                BatteryStats.HistoryItem.EVENT_ALARM | BatteryStats.HistoryItem.EVENT_FLAG_START,
+                "foo", APP_UID, 3_600_000, 90, 3_000_000);
+
+        assertThat(iterator.next(item)).isTrue();
+        assertHistoryItem(item,
+                BatteryStats.HistoryItem.CMD_UPDATE,
+                BatteryStats.HistoryItem.EVENT_ALARM | BatteryStats.HistoryItem.EVENT_FLAG_FINISH,
+                "foo", APP_UID, 3_600_000, 90, 3_001_000);
+
+        assertThat(iterator.next(item)).isFalse();
+    }
+
+    private void assertHistoryItem(BatteryStats.HistoryItem item, int command, int eventCode,
+            String tag, int uid, int batteryChargeUah, int batteryLevel, long elapsedTimeMs) {
+        assertThat(item.cmd).isEqualTo(command);
+        assertThat(item.eventCode).isEqualTo(eventCode);
+        if (tag == null) {
+            assertThat(item.eventTag).isNull();
+        } else {
+            assertThat(item.eventTag.string).isEqualTo(tag);
+            assertThat(item.eventTag.uid).isEqualTo(uid);
+        }
+        assertThat(item.batteryChargeUah).isEqualTo(batteryChargeUah);
+        assertThat(item.batteryLevel).isEqualTo(batteryLevel);
+
+        assertThat(item.time).isEqualTo(elapsedTimeMs);
+    }
+}
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 355ac6d..23ea508 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
@@ -35,6 +35,7 @@
 import java.util.List;
 
 @SmallTest
+@SkipPresubmit("b/180015146")
 @RunWith(AndroidJUnit4.class)
 public class BatteryUsageStatsTest {
 
@@ -66,33 +67,36 @@
         final MockBatteryStatsImpl batteryStats = new MockBatteryStatsImpl(clocks);
         final BatteryStatsImpl.Uid batteryStatsUid = batteryStats.getUidStatsLocked(2000);
 
-        final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(1, 1);
-        builder.setDischargePercentage(20);
-        builder.setDischargedPowerRange(1000, 2000);
+        final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(1, 1)
+                .setDischargePercentage(20)
+                .setDischargedPowerRange(1000, 2000);
 
-        final UidBatteryConsumer.Builder uidBatteryConsumerBuilder =
-                builder.getOrCreateUidBatteryConsumerBuilder(batteryStatsUid);
-        uidBatteryConsumerBuilder.setPackageWithHighestDrain("foo");
-        uidBatteryConsumerBuilder.setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, 300);
-        uidBatteryConsumerBuilder.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, 400);
-        uidBatteryConsumerBuilder.setConsumedPowerForCustomComponent(
-                BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 500);
-        uidBatteryConsumerBuilder.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU, 600);
-        uidBatteryConsumerBuilder.setUsageDurationMillis(
-                BatteryConsumer.TIME_COMPONENT_CPU_FOREGROUND, 700);
-        uidBatteryConsumerBuilder.setUsageDurationForCustomComponentMillis(
-                BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID, 800);
+        builder.getOrCreateUidBatteryConsumerBuilder(batteryStatsUid)
+                .setPackageWithHighestDrain("foo")
+                .setTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND, 1000)
+                .setTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND, 2000)
+                .setConsumedPower(
+                        BatteryConsumer.POWER_COMPONENT_USAGE, 300)
+                .setConsumedPower(
+                        BatteryConsumer.POWER_COMPONENT_CPU, 400)
+                .setConsumedPowerForCustomComponent(
+                        BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 500)
+                .setUsageDurationMillis(
+                        BatteryConsumer.TIME_COMPONENT_CPU, 600)
+                .setUsageDurationMillis(
+                        BatteryConsumer.TIME_COMPONENT_CPU_FOREGROUND, 700)
+                .setUsageDurationForCustomComponentMillis(
+                        BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID, 800);
 
-        final SystemBatteryConsumer.Builder systemBatteryConsumerBuilder =
-                builder.getOrCreateSystemBatteryConsumerBuilder(
-                        SystemBatteryConsumer.DRAIN_TYPE_CAMERA);
-        systemBatteryConsumerBuilder.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, 10100);
-        systemBatteryConsumerBuilder.setConsumedPowerForCustomComponent(
-                BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 10200);
-        systemBatteryConsumerBuilder.setUsageDurationMillis(
-                BatteryConsumer.TIME_COMPONENT_CPU, 10300);
-        systemBatteryConsumerBuilder.setUsageDurationForCustomComponentMillis(
-                BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID, 10400);
+        builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_CAMERA)
+                .setConsumedPower(
+                        BatteryConsumer.POWER_COMPONENT_CPU, 10100)
+                .setConsumedPowerForCustomComponent(
+                        BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 10200)
+                .setUsageDurationMillis(
+                        BatteryConsumer.TIME_COMPONENT_CPU, 10300)
+                .setUsageDurationForCustomComponentMillis(
+                        BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID, 10400);
 
         return builder.build();
     }
@@ -108,6 +112,10 @@
         for (UidBatteryConsumer uidBatteryConsumer : uidBatteryConsumers) {
             if (uidBatteryConsumer.getUid() == 2000) {
                 assertThat(uidBatteryConsumer.getPackageWithHighestDrain()).isEqualTo("foo");
+                assertThat(uidBatteryConsumer.getTimeInStateMs(
+                        UidBatteryConsumer.STATE_FOREGROUND)).isEqualTo(1000);
+                assertThat(uidBatteryConsumer.getTimeInStateMs(
+                        UidBatteryConsumer.STATE_BACKGROUND)).isEqualTo(2000);
                 assertThat(uidBatteryConsumer.getConsumedPower(
                         BatteryConsumer.POWER_COMPONENT_USAGE)).isEqualTo(300);
                 assertThat(uidBatteryConsumer.getConsumedPower(
diff --git a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
index e559471..f6aa08b 100644
--- a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
@@ -43,6 +43,7 @@
             .setAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX, 100.0);
 
     @Test
+    @SkipPresubmit("b/180015146")
     public void testTimerBasedModel() {
         setDurationsAndPower(mStatsRule.getUidStats(Process.BLUETOOTH_UID)
                         .getOrCreateBluetoothControllerActivityLocked(),
@@ -73,6 +74,7 @@
     }
 
     @Test
+    @SkipPresubmit("b/180015146")
     public void testReportedPowerBasedModel() {
         setDurationsAndPower(mStatsRule.getUidStats(Process.BLUETOOTH_UID)
                         .getOrCreateBluetoothControllerActivityLocked(),
diff --git a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
index a80f5a0..4fe7d70 100644
--- a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
@@ -382,6 +382,7 @@
     }
 
     @Test
+    @SkipPresubmit("b/180015146 flakey")
     public void testCpuFreqTimes_stateFgService() throws Exception {
         if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
             Log.w(TAG, "Skipping " + testName.getMethodName()
@@ -514,6 +515,7 @@
     }
 
     @Test
+    @SkipPresubmit("b/180015146")
     public void testCpuFreqTimes_trackingDisabled() throws Exception {
         if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
             Log.w(TAG, "Skipping " + testName.getMethodName()
diff --git a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
index 9cf0d37..e691beb 100644
--- a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
@@ -92,6 +92,7 @@
     }
 
     @Test
+    @SkipPresubmit("b/180015146")
     public void testTimerBasedModel() {
         when(mMockUserInfoProvider.exists(anyInt())).thenReturn(true);
 
diff --git a/core/tests/coretests/src/com/android/internal/os/CustomMeasuredPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/CustomMeasuredPowerCalculatorTest.java
index a4ea892..f298f59 100644
--- a/core/tests/coretests/src/com/android/internal/os/CustomMeasuredPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/CustomMeasuredPowerCalculatorTest.java
@@ -42,6 +42,7 @@
     public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule();
 
     @Test
+    @SkipPresubmit("b/180015146")
     public void testMeasuredEnergyCopiedIntoBatteryConsumers() {
         final BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
         SparseLongArray uidEnergies = new SparseLongArray();
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java
index 7dca0cb..177f348 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java
@@ -87,6 +87,7 @@
     }
 
     @Test
+    @SkipPresubmit("b/180015146")
     public void testThrottler() throws Exception {
         mReader = new KernelCpuUidUserSysTimeReader(
                 new KernelCpuProcStringReader(mTestFile.getAbsolutePath()), true);
diff --git a/core/tests/coretests/src/com/android/internal/os/SkipPresubmit.java b/core/tests/coretests/src/com/android/internal/os/SkipPresubmit.java
new file mode 100644
index 0000000..d03ed66
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/SkipPresubmit.java
@@ -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.
+ */
+
+package com.android.internal.os;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Annotation to skip a test from TEST_MAPPING presubmit. */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface SkipPresubmit {
+    /** The optional reason why the test is ignored. */
+    String value() default "";
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
index dfbf28b..b5282e9 100644
--- a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
@@ -78,6 +78,7 @@
     }
 
     @Test
+    @SkipPresubmit("b/180015146")
     public void testPowerProfileBasedModel() {
         when(mMockUserInfoProvider.exists(anyInt())).thenReturn(true);
 
diff --git a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
new file mode 100644
index 0000000..e100545
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
@@ -0,0 +1,128 @@
+/*
+ * 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.os;
+
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.net.NetworkCapabilities;
+import android.net.NetworkStats;
+import android.os.BatteryConsumer;
+import android.os.Process;
+import android.os.SystemBatteryConsumer;
+import android.os.UidBatteryConsumer;
+import android.os.WorkSource;
+import android.os.connectivity.WifiActivityEnergyInfo;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class WifiPowerCalculatorTest {
+    private static final double PRECISION = 0.00001;
+
+    private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
+
+    @Rule
+    public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
+            .setAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_IDLE, 360.0)
+            .setAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_RX, 480.0)
+            .setAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_TX, 720.0)
+            .setAveragePower(PowerProfile.POWER_WIFI_ON, 360.0)
+            .setAveragePower(PowerProfile.POWER_WIFI_SCAN, 480.0)
+            .setAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN, 720.0)
+            .setAveragePower(PowerProfile.POWER_WIFI_ACTIVE, 1080.0);
+
+    @Test
+    public void testPowerControllerBasedModel() {
+        BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
+
+        batteryStats.noteNetworkInterfaceForTransports("wifi",
+                new int[]{NetworkCapabilities.TRANSPORT_WIFI});
+
+        NetworkStats networkStats = new NetworkStats(10000, 1)
+                .insertEntry("wifi", APP_UID, 0, 0, 1000, 100, 2000, 20, 100)
+                .insertEntry("wifi", Process.WIFI_UID, 0, 0, 1111, 111, 2222, 22, 111);
+        mStatsRule.setNetworkStats(networkStats);
+
+        WifiActivityEnergyInfo energyInfo = new WifiActivityEnergyInfo(10000,
+                WifiActivityEnergyInfo.STACK_STATE_STATE_ACTIVE, 1000, 2000, 3000, 4000);
+
+        batteryStats.updateWifiState(energyInfo, 1000, 1000);
+
+        WifiPowerCalculator calculator = new WifiPowerCalculator(mStatsRule.getPowerProfile());
+        mStatsRule.apply(calculator);
+
+        UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
+        assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
+                .isEqualTo(1423);
+        assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
+                .isWithin(PRECISION).of(0.2214666);
+
+        SystemBatteryConsumer systemConsumer =
+                mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_WIFI);
+        assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
+                .isEqualTo(5577);
+        assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
+                .isWithin(PRECISION).of(0.645200);
+    }
+
+    @Test
+    public void testTimerBasedModel() {
+        BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
+
+        batteryStats.noteNetworkInterfaceForTransports("wifi",
+                new int[]{NetworkCapabilities.TRANSPORT_WIFI});
+
+        NetworkStats networkStats = new NetworkStats(10000, 1)
+                .insertEntry("wifi", APP_UID, 0, 0, 1000, 100, 2000, 20, 100)
+                .insertEntry("wifi", Process.WIFI_UID, 0, 0, 1111, 111, 2222, 22, 111);
+        mStatsRule.setNetworkStats(networkStats);
+
+        batteryStats.noteWifiScanStartedLocked(APP_UID, 1000, 1000);
+        batteryStats.noteWifiScanStoppedLocked(APP_UID, 2000, 2000);
+        batteryStats.noteWifiRunningLocked(new WorkSource(APP_UID), 3000, 3000);
+        batteryStats.noteWifiStoppedLocked(new WorkSource(APP_UID), 4000, 4000);
+        batteryStats.noteWifiRunningLocked(new WorkSource(Process.WIFI_UID), 1111, 2222);
+        batteryStats.noteWifiStoppedLocked(new WorkSource(Process.WIFI_UID), 3333, 4444);
+
+        // Don't pass WifiActivityEnergyInfo, making WifiPowerCalculator rely exclusively
+        // on the packet counts.
+        batteryStats.updateWifiState(/* energyInfo */ null, 1000, 1000);
+
+        WifiPowerCalculator calculator = new WifiPowerCalculator(mStatsRule.getPowerProfile());
+        mStatsRule.apply(calculator);
+
+        UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
+        assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
+                .isEqualTo(1000);
+        assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
+                .isWithin(PRECISION).of(0.8231573);
+
+        SystemBatteryConsumer systemConsumer =
+                mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_WIFI);
+        assertThat(systemConsumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_WIFI))
+                .isEqualTo(2222);
+        assertThat(systemConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
+                .isWithin(PRECISION).of(0.8759216);
+    }
+}
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 5fd5a78..d217bce 100644
--- a/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
@@ -81,11 +81,11 @@
 
         final MeasuredEnergyStats stats
                 = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
-        stats.updateCustomBucket(0, 50, true);
-        stats.updateCustomBucket(1, 60, true);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40);
+        stats.updateCustomBucket(0, 50);
+        stats.updateCustomBucket(1, 60);
 
         final MeasuredEnergyStats newStats = MeasuredEnergyStats.createFromTemplate(stats);
 
@@ -114,11 +114,11 @@
 
         final MeasuredEnergyStats stats
                 = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
-        stats.updateCustomBucket(0, 50, true);
-        stats.updateCustomBucket(1, 60, true);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40);
+        stats.updateCustomBucket(0, 50);
+        stats.updateCustomBucket(1, 60);
 
         final Parcel parcel = Parcel.obtain();
         stats.writeToParcel(parcel);
@@ -149,11 +149,11 @@
 
         final MeasuredEnergyStats stats
                 = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
-        stats.updateCustomBucket(0, 50, true);
-        stats.updateCustomBucket(1, 60, true);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40);
+        stats.updateCustomBucket(0, 50);
+        stats.updateCustomBucket(1, 60);
 
         final Parcel parcel = Parcel.obtain();
         MeasuredEnergyStats.writeSummaryToParcel(stats, parcel, false);
@@ -185,17 +185,17 @@
 
         final MeasuredEnergyStats template
                 = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
-        template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
-        template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
-        template.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
-        template.updateCustomBucket(0, 50, true);
+        template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10);
+        template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5);
+        template.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40);
+        template.updateCustomBucket(0, 50);
 
         final MeasuredEnergyStats stats = MeasuredEnergyStats.createFromTemplate(template);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 200, true);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 7, true);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 63, true);
-        stats.updateCustomBucket(0, 315, true);
-        stats.updateCustomBucket(1, 316, true);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 200);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 7);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 63);
+        stats.updateCustomBucket(0, 315);
+        stats.updateCustomBucket(1, 316);
 
         final Parcel parcel = Parcel.obtain();
         MeasuredEnergyStats.writeSummaryToParcel(stats, parcel, false);
@@ -243,8 +243,8 @@
         final MeasuredEnergyStats stats
                 = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
         // Accumulate energy in one bucket and one custom bucket, the rest should be zero
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 200, true);
-        stats.updateCustomBucket(1, 60, true);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 200);
+        stats.updateCustomBucket(1, 60);
 
         // Let's try parcelling with including zeros
         final Parcel includeZerosParcel = Parcel.obtain();
@@ -305,11 +305,11 @@
 
         final MeasuredEnergyStats stats
                 = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
-        stats.updateCustomBucket(0, 50, true);
-        stats.updateCustomBucket(1, 60, true);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40);
+        stats.updateCustomBucket(0, 50);
+        stats.updateCustomBucket(1, 60);
 
         final Parcel parcel = Parcel.obtain();
         MeasuredEnergyStats.writeSummaryToParcel(stats, parcel, false);
@@ -331,14 +331,14 @@
 
         final MeasuredEnergyStats template
                 = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
-        template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
-        template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
-        template.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
-        template.updateCustomBucket(0, 50, true);
+        template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10);
+        template.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5);
+        template.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40);
+        template.updateCustomBucket(0, 50);
 
         final MeasuredEnergyStats stats = MeasuredEnergyStats.createFromTemplate(template);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 0L, true);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 7L, true);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 0L);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 7L);
 
         final Parcel parcel = Parcel.obtain();
         MeasuredEnergyStats.writeSummaryToParcel(stats, parcel, false);
@@ -369,14 +369,14 @@
 
         final MeasuredEnergyStats stats
                 = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_DOZE, 30, true);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_DOZE, 30);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5);
 
-        stats.updateCustomBucket(0, 50, true);
-        stats.updateCustomBucket(1, 60, true);
-        stats.updateCustomBucket(0, 3, true);
+        stats.updateCustomBucket(0, 50);
+        stats.updateCustomBucket(1, 60);
+        stats.updateCustomBucket(0, 3);
 
         assertEquals(15, stats.getAccumulatedStandardBucketEnergy(ENERGY_BUCKET_SCREEN_ON));
         assertEquals(ENERGY_DATA_UNAVAILABLE,
@@ -409,10 +409,10 @@
         final MeasuredEnergyStats stats
                 = new MeasuredEnergyStats(new boolean[NUMBER_STANDARD_ENERGY_BUCKETS], 3);
 
-        stats.updateCustomBucket(0, 50, true);
-        stats.updateCustomBucket(1, 60, true);
-        stats.updateCustomBucket(2, 13, true);
-        stats.updateCustomBucket(1, 70, true);
+        stats.updateCustomBucket(0, 50);
+        stats.updateCustomBucket(1, 60);
+        stats.updateCustomBucket(2, 13);
+        stats.updateCustomBucket(1, 70);
 
         final long[] output = stats.getAccumulatedCustomBucketEnergies();
         assertEquals(3, output.length);
@@ -449,11 +449,11 @@
 
         final MeasuredEnergyStats stats
                 = new MeasuredEnergyStats(supportedStandardBuckets, numCustomBuckets);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10, true);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5, true);
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40, true);
-        stats.updateCustomBucket(0, 50, true);
-        stats.updateCustomBucket(1, 60, true);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 10);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 5);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_OTHER, 40);
+        stats.updateCustomBucket(0, 50);
+        stats.updateCustomBucket(1, 60);
 
         MeasuredEnergyStats.resetIfNotNull(stats);
         // All energy should be reset to 0
@@ -471,10 +471,10 @@
         }
 
         // Values should increase as usual.
-        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 70, true);
+        stats.updateStandardBucket(ENERGY_BUCKET_SCREEN_ON, 70);
         assertEquals(70L, stats.getAccumulatedStandardBucketEnergy(ENERGY_BUCKET_SCREEN_ON));
 
-        stats.updateCustomBucket(1, 12, true);
+        stats.updateCustomBucket(1, 12);
         assertEquals(12L, stats.getAccumulatedCustomBucketEnergy(1));
     }
 
diff --git a/core/tests/devicestatetests/Android.bp b/core/tests/devicestatetests/Android.bp
index 409b77b..7748de5 100644
--- a/core/tests/devicestatetests/Android.bp
+++ b/core/tests/devicestatetests/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+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_test {
     name: "FrameworksCoreDeviceStateManagerTests",
     // Include all test java files
@@ -19,6 +28,7 @@
     static_libs: [
         "androidx.test.rules",
         "frameworks-base-testutils",
+        "mockito-target-minus-junit4",
     ],
     libs: ["android.test.runner"],
     platform_apis: true,
diff --git a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateInfoTest.java b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateInfoTest.java
new file mode 100644
index 0000000..dcef0a7
--- /dev/null
+++ b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateInfoTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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.devicestate;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Unit tests for {@link DeviceStateInfo}.
+ * <p/>
+ * Run with <code>atest DeviceStateInfoTest</code>.
+ */
+@RunWith(JUnit4.class)
+@SmallTest
+public final class DeviceStateInfoTest {
+    @Test
+    public void create() {
+        final int[] supportedStates = new int[] { 0, 1, 2 };
+        final int baseState = 0;
+        final int currentState = 2;
+
+        final DeviceStateInfo info = new DeviceStateInfo(supportedStates, baseState, currentState);
+        assertNotNull(info.supportedStates);
+        assertEquals(supportedStates, info.supportedStates);
+        assertEquals(baseState, info.baseState);
+        assertEquals(currentState, info.currentState);
+    }
+
+    @Test
+    public void equals() {
+        final int[] supportedStates = new int[] { 0, 1, 2 };
+        final int baseState = 0;
+        final int currentState = 2;
+
+        final DeviceStateInfo info = new DeviceStateInfo(supportedStates, baseState, currentState);
+        assertTrue(info.equals(info));
+
+        final DeviceStateInfo sameInfo = new DeviceStateInfo(supportedStates, baseState,
+                currentState);
+        assertTrue(info.equals(sameInfo));
+
+        final DeviceStateInfo differentInfo = new DeviceStateInfo(new int[]{ 0, 2}, baseState,
+                currentState);
+        assertFalse(info.equals(differentInfo));
+    }
+
+    @Test
+    public void diff_sameObject() {
+        final int[] supportedStates = new int[] { 0, 1, 2 };
+        final int baseState = 0;
+        final int currentState = 2;
+
+        final DeviceStateInfo info = new DeviceStateInfo(supportedStates, baseState, currentState);
+        assertEquals(0, info.diff(info));
+    }
+
+    @Test
+    public void diff_differentSupportedStates() {
+        final DeviceStateInfo info = new DeviceStateInfo(new int[] { 1 }, 0, 0);
+        final DeviceStateInfo otherInfo = new DeviceStateInfo(new int[] { 2 }, 0, 0);
+        final int diff = info.diff(otherInfo);
+        assertTrue((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0);
+        assertFalse((diff & DeviceStateInfo.CHANGED_BASE_STATE) > 0);
+        assertFalse((diff & DeviceStateInfo.CHANGED_CURRENT_STATE) > 0);
+    }
+
+    @Test
+    public void diff_differentNonOverrideState() {
+        final DeviceStateInfo info = new DeviceStateInfo(new int[] { 1 }, 1, 0);
+        final DeviceStateInfo otherInfo = new DeviceStateInfo(new int[] { 1 }, 2, 0);
+        final int diff = info.diff(otherInfo);
+        assertFalse((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0);
+        assertTrue((diff & DeviceStateInfo.CHANGED_BASE_STATE) > 0);
+        assertFalse((diff & DeviceStateInfo.CHANGED_CURRENT_STATE) > 0);
+    }
+
+    @Test
+    public void diff_differentState() {
+        final DeviceStateInfo info = new DeviceStateInfo(new int[] { 1 }, 0, 1);
+        final DeviceStateInfo otherInfo = new DeviceStateInfo(new int[] { 1 }, 0, 2);
+        final int diff = info.diff(otherInfo);
+        assertFalse((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0);
+        assertFalse((diff & DeviceStateInfo.CHANGED_BASE_STATE) > 0);
+        assertTrue((diff & DeviceStateInfo.CHANGED_CURRENT_STATE) > 0);
+    }
+
+    @Test
+    public void writeToParcel() {
+        final int[] supportedStates = new int[] { 0, 1, 2 };
+        final int nonOverrideState = 0;
+        final int state = 2;
+        final DeviceStateInfo originalInfo =
+                new DeviceStateInfo(supportedStates, nonOverrideState, state);
+
+        final Parcel parcel = Parcel.obtain();
+        originalInfo.writeToParcel(parcel, 0 /* flags */);
+        parcel.setDataPosition(0);
+
+        final DeviceStateInfo info = DeviceStateInfo.CREATOR.createFromParcel(parcel);
+        assertEquals(originalInfo, info);
+    }
+}
diff --git a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
index e7fdfb8..79b4d8b 100644
--- a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
+++ b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
@@ -16,11 +16,15 @@
 
 package android.hardware.devicestate;
 
-import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
-import android.annotation.Nullable;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback;
 import android.os.IBinder;
 import android.os.RemoteException;
 
@@ -32,6 +36,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
+import org.mockito.Mockito;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -58,42 +63,75 @@
     }
 
     @Test
-    public void registerListener() {
-        mService.setBaseState(DEFAULT_DEVICE_STATE);
+    public void registerCallback() {
+        DeviceStateCallback callback1 = mock(DeviceStateCallback.class);
+        DeviceStateCallback callback2 = mock(DeviceStateCallback.class);
 
-        TestDeviceStateListener listener1 = new TestDeviceStateListener();
-        TestDeviceStateListener listener2 = new TestDeviceStateListener();
-
-        mDeviceStateManagerGlobal.registerDeviceStateListener(listener1,
+        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback1,
                 ConcurrentUtils.DIRECT_EXECUTOR);
-        mDeviceStateManagerGlobal.registerDeviceStateListener(listener2,
+        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback2,
                 ConcurrentUtils.DIRECT_EXECUTOR);
-        assertEquals(DEFAULT_DEVICE_STATE, listener1.getLastReportedState().intValue());
-        assertEquals(DEFAULT_DEVICE_STATE, listener2.getLastReportedState().intValue());
 
+        // Verify initial callbacks
+        verify(callback1).onSupportedStatesChanged(eq(mService.getSupportedStates()));
+        verify(callback1).onBaseStateChanged(eq(mService.getBaseState()));
+        verify(callback1).onStateChanged(eq(mService.getMergedState()));
+        verify(callback2).onSupportedStatesChanged(eq(mService.getSupportedStates()));
+        verify(callback2).onBaseStateChanged(eq(mService.getBaseState()));
+        verify(callback2).onStateChanged(eq(mService.getMergedState()));
+
+        Mockito.reset(callback1);
+        Mockito.reset(callback2);
+
+        // Change the supported states and verify callback
+        mService.setSupportedStates(new int[]{ DEFAULT_DEVICE_STATE });
+        verify(callback1).onSupportedStatesChanged(eq(mService.getSupportedStates()));
+        verify(callback2).onSupportedStatesChanged(eq(mService.getSupportedStates()));
+        mService.setSupportedStates(new int[]{ DEFAULT_DEVICE_STATE, OTHER_DEVICE_STATE });
+
+        Mockito.reset(callback1);
+        Mockito.reset(callback2);
+
+        // Change the base state and verify callback
         mService.setBaseState(OTHER_DEVICE_STATE);
-        assertEquals(OTHER_DEVICE_STATE, listener1.getLastReportedState().intValue());
-        assertEquals(OTHER_DEVICE_STATE, listener2.getLastReportedState().intValue());
+        verify(callback1).onBaseStateChanged(eq(mService.getBaseState()));
+        verify(callback1).onStateChanged(eq(mService.getMergedState()));
+        verify(callback2).onBaseStateChanged(eq(mService.getBaseState()));
+        verify(callback2).onStateChanged(eq(mService.getMergedState()));
+
+        Mockito.reset(callback1);
+        Mockito.reset(callback2);
+
+        // Change the requested state and verify callback
+        DeviceStateRequest request = DeviceStateRequest.newBuilder(DEFAULT_DEVICE_STATE).build();
+        mDeviceStateManagerGlobal.requestState(request, null /* executor */, null /* callback */);
+
+        verify(callback1).onStateChanged(eq(mService.getMergedState()));
+        verify(callback2).onStateChanged(eq(mService.getMergedState()));
     }
 
     @Test
-    public void unregisterListener() {
-        mService.setBaseState(DEFAULT_DEVICE_STATE);
+    public void unregisterCallback() {
+        DeviceStateCallback callback = mock(DeviceStateCallback.class);
 
-        TestDeviceStateListener listener = new TestDeviceStateListener();
-
-        mDeviceStateManagerGlobal.registerDeviceStateListener(listener,
+        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback,
                 ConcurrentUtils.DIRECT_EXECUTOR);
-        assertEquals(DEFAULT_DEVICE_STATE, listener.getLastReportedState().intValue());
 
-        mDeviceStateManagerGlobal.unregisterDeviceStateListener(listener);
+        // Verify initial callbacks
+        verify(callback).onSupportedStatesChanged(eq(mService.getSupportedStates()));
+        verify(callback).onBaseStateChanged(eq(mService.getBaseState()));
+        verify(callback).onStateChanged(eq(mService.getMergedState()));
+        Mockito.reset(callback);
 
+        mDeviceStateManagerGlobal.unregisterDeviceStateCallback(callback);
+
+        mService.setSupportedStates(new int[]{OTHER_DEVICE_STATE});
         mService.setBaseState(OTHER_DEVICE_STATE);
-        assertEquals(DEFAULT_DEVICE_STATE, listener.getLastReportedState().intValue());
+        verifyZeroInteractions(callback);
     }
 
     @Test
-    public void submittingRequestRegisteredCallback() {
+    public void submittingRequestRegistersCallback() {
         assertTrue(mService.mCallbacks.isEmpty());
 
         DeviceStateRequest request = DeviceStateRequest.newBuilder(DEFAULT_DEVICE_STATE).build();
@@ -104,37 +142,22 @@
 
     @Test
     public void submitRequest() {
-        mService.setBaseState(DEFAULT_DEVICE_STATE);
-
-        TestDeviceStateListener listener = new TestDeviceStateListener();
-        mDeviceStateManagerGlobal.registerDeviceStateListener(listener,
+        DeviceStateCallback callback = mock(DeviceStateCallback.class);
+        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback,
                 ConcurrentUtils.DIRECT_EXECUTOR);
 
-        assertEquals(DEFAULT_DEVICE_STATE, listener.getLastReportedState().intValue());
+        verify(callback).onStateChanged(eq(mService.getBaseState()));
+        Mockito.reset(callback);
 
         DeviceStateRequest request = DeviceStateRequest.newBuilder(OTHER_DEVICE_STATE).build();
         mDeviceStateManagerGlobal.requestState(request, null /* executor */, null /* callback */);
 
-        assertEquals(OTHER_DEVICE_STATE, listener.getLastReportedState().intValue());
+        verify(callback).onStateChanged(eq(OTHER_DEVICE_STATE));
+        Mockito.reset(callback);
 
         mDeviceStateManagerGlobal.cancelRequest(request);
 
-        assertEquals(DEFAULT_DEVICE_STATE, listener.getLastReportedState().intValue());
-    }
-
-    private final class TestDeviceStateListener implements DeviceStateManager.DeviceStateListener {
-        @Nullable
-        private Integer mLastReportedDeviceState;
-
-        @Override
-        public void onDeviceStateChanged(int deviceState) {
-            mLastReportedDeviceState = deviceState;
-        }
-
-        @Nullable
-        public Integer getLastReportedState() {
-            return mLastReportedDeviceState;
-        }
+        verify(callback).onStateChanged(eq(mService.getBaseState()));
     }
 
     private static final class TestDeviceStateManagerService extends IDeviceStateManager.Stub {
@@ -150,12 +173,34 @@
             }
         }
 
+        private int[] mSupportedStates = new int[] { DEFAULT_DEVICE_STATE, OTHER_DEVICE_STATE };
         private int mBaseState = DEFAULT_DEVICE_STATE;
-        private int mMergedState = DEFAULT_DEVICE_STATE;
         private ArrayList<Request> mRequests = new ArrayList<>();
 
         private Set<IDeviceStateManagerCallback> mCallbacks = new HashSet<>();
 
+        private DeviceStateInfo getInfo() {
+            final int mergedState = mRequests.isEmpty()
+                    ? mBaseState : mRequests.get(mRequests.size() - 1).state;
+            return new DeviceStateInfo(mSupportedStates, mBaseState, mergedState);
+        }
+
+        private void notifyDeviceStateInfoChanged() {
+            final DeviceStateInfo info = getInfo();
+            for (IDeviceStateManagerCallback callback : mCallbacks) {
+                try {
+                    callback.onDeviceStateInfoChanged(info);
+                } catch (RemoteException e) {
+                    // Do nothing. Should never happen.
+                }
+            }
+        }
+
+        @Override
+        public DeviceStateInfo getDeviceStateInfo() {
+            return getInfo();
+        }
+
         @Override
         public void registerCallback(IDeviceStateManagerCallback callback) {
             if (mCallbacks.contains(callback)) {
@@ -163,16 +208,6 @@
             }
 
             mCallbacks.add(callback);
-            try {
-                callback.onDeviceStateChanged(mMergedState);
-            } catch (RemoteException e) {
-                // Do nothing. Should never happen.
-            }
-        }
-
-        @Override
-        public int[] getSupportedDeviceStates() {
-            return new int[] { DEFAULT_DEVICE_STATE, OTHER_DEVICE_STATE };
         }
 
         @Override
@@ -190,7 +225,7 @@
 
             final Request request = new Request(token, state, flags);
             mRequests.add(request);
-            notifyStateChangedIfNeeded();
+            notifyDeviceStateInfoChanged();
 
             for (IDeviceStateManagerCallback callback : mCallbacks) {
                 try {
@@ -223,32 +258,29 @@
                     // Do nothing. Should never happen.
                 }
             }
-            notifyStateChangedIfNeeded();
+            notifyDeviceStateInfoChanged();
+        }
+
+        public void setSupportedStates(int[] states) {
+            mSupportedStates = states;
+            notifyDeviceStateInfoChanged();
+        }
+
+        public int[] getSupportedStates() {
+            return mSupportedStates;
         }
 
         public void setBaseState(int state) {
             mBaseState = state;
-            notifyStateChangedIfNeeded();
+            notifyDeviceStateInfoChanged();
         }
 
-        private void notifyStateChangedIfNeeded() {
-            final int originalMergedState = mMergedState;
+        public int getBaseState() {
+            return mBaseState;
+        }
 
-            if (!mRequests.isEmpty()) {
-                mMergedState = mRequests.get(mRequests.size() - 1).state;
-            } else {
-                mMergedState = mBaseState;
-            }
-
-            if (mMergedState != originalMergedState) {
-                for (IDeviceStateManagerCallback callback : mCallbacks) {
-                    try {
-                        callback.onDeviceStateChanged(mMergedState);
-                    } catch (RemoteException e) {
-                        // Do nothing. Should never happen.
-                    }
-                }
-            }
+        public int getMergedState() {
+            return getInfo().currentState;
         }
     }
 }
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
index d2b20b4..0808186 100644
--- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -298,7 +298,7 @@
                     null /* pendingResults */, null /* pendingNewIntents */,
                     null /* activityOptions */, true /* isForward */, null /* profilerInfo */,
                     mThread /* client */, null /* asssitToken */,
-                    null /* fixedRotationAdjustments */);
+                    null /* fixedRotationAdjustments */, null /* shareableActivityToken */);
         }
 
         @Override
diff --git a/data/etc/car/Android.bp b/data/etc/car/Android.bp
index f6d7685..2f41b90 100644
--- a/data/etc/car/Android.bp
+++ b/data/etc/car/Android.bp
@@ -173,3 +173,10 @@
     src: "com.android.car.shell.xml",
     filename_from_src: true,
 }
+
+prebuilt_etc {
+    name: "allowed_privapp_com.android.car.activityresolver",
+    sub_dir: "permissions",
+    src: "com.android.car.activityresolver.xml",
+    filename_from_src: true,
+}
diff --git a/data/etc/car/android.car.cluster.xml b/data/etc/car/android.car.cluster.xml
index d7f29da..de3acca 100644
--- a/data/etc/car/android.car.cluster.xml
+++ b/data/etc/car/android.car.cluster.xml
@@ -20,5 +20,7 @@
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
         <permission name="android.permission.MANAGE_USERS"/>
         <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+        <permission name="android.car.permission.CAR_ENGINE_DETAILED"/>
+        <permission name="android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL"/>
     </privapp-permissions>
 </permissions>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view.xml b/data/etc/car/com.android.car.activityresolver.xml
similarity index 73%
copy from packages/SystemUI/res/layout/udfps_animation_view.xml
copy to data/etc/car/com.android.car.activityresolver.xml
index 380dd85..d48bc15 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view.xml
+++ b/data/etc/car/com.android.car.activityresolver.xml
@@ -14,8 +14,8 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/udfps_animation_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"/>
+<permissions>
+    <privapp-permissions package="com.android.car.activityresolver">
+        <permission name="android.permission.MANAGE_USERS"/>
+    </privapp-permissions>
+</permissions>
diff --git a/data/etc/car/com.android.car.bugreport.xml b/data/etc/car/com.android.car.bugreport.xml
index c3642d88..2ff9835 100644
--- a/data/etc/car/com.android.car.bugreport.xml
+++ b/data/etc/car/com.android.car.bugreport.xml
@@ -21,5 +21,6 @@
         <permission name="android.permission.READ_LOGS"/>
         <permission name="android.permission.MANAGE_USERS"/>
         <permission name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"/>
+        <permission name="android.car.permission.CAR_DRIVING_STATE"/>
     </privapp-permissions>
   </permissions>
diff --git a/data/etc/car/com.android.car.carlauncher.xml b/data/etc/car/com.android.car.carlauncher.xml
index 0e49284..ac16af3 100644
--- a/data/etc/car/com.android.car.carlauncher.xml
+++ b/data/etc/car/com.android.car.carlauncher.xml
@@ -17,9 +17,10 @@
 <permissions>
     <privapp-permissions package="com.android.car.carlauncher">
         <permission name="android.permission.ACTIVITY_EMBEDDING"/>
-	<permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
+        <permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
         <permission name="android.permission.MANAGE_USERS"/>
         <permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
         <permission name="android.permission.PACKAGE_USAGE_STATS"/>
+        <permission name="android.car.permission.ACCESS_CAR_PROJECTION_STATUS"/>
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/car/com.android.car.dialer.xml b/data/etc/car/com.android.car.dialer.xml
index d44f5a1..61ae53a 100644
--- a/data/etc/car/com.android.car.dialer.xml
+++ b/data/etc/car/com.android.car.dialer.xml
@@ -18,5 +18,6 @@
     <privapp-permissions package="com.android.car.dialer">
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
         <permission name="android.permission.MODIFY_PHONE_STATE"/>
+        <permission name="android.car.permission.ACCESS_CAR_PROJECTION_STATUS"/>
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/car/com.android.car.hvac.xml b/data/etc/car/com.android.car.hvac.xml
index d3631e0..534d44d 100644
--- a/data/etc/car/com.android.car.hvac.xml
+++ b/data/etc/car/com.android.car.hvac.xml
@@ -17,5 +17,6 @@
 <permissions>
     <privapp-permissions package="com.android.car.hvac">
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+        <permission name="android.car.permission.CONTROL_CAR_CLIMATE"/>
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/car/com.android.car.radio.xml b/data/etc/car/com.android.car.radio.xml
index d7853ab..ed8652c 100644
--- a/data/etc/car/com.android.car.radio.xml
+++ b/data/etc/car/com.android.car.radio.xml
@@ -18,5 +18,7 @@
     <privapp-permissions package="com.android.car.radio">
         <permission name="android.permission.ACCESS_BROADCAST_RADIO"/>
         <permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
+        <permission name="android.car.permission.CAR_CONTROL_AUDIO_SETTINGS"/>
+        <permission name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME"/>
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/car/com.google.android.car.kitchensink.xml b/data/etc/car/com.google.android.car.kitchensink.xml
index bd30d7a..e6196c2 100644
--- a/data/etc/car/com.google.android.car.kitchensink.xml
+++ b/data/etc/car/com.google.android.car.kitchensink.xml
@@ -51,5 +51,41 @@
 
         <!-- use for rotary fragment to enable/disable packages related to rotary -->
         <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
+
+        <!-- CarService permissions -->
+        <!-- TODO: Explain why so many permissions are required -->
+        <permission name="android.car.permission.ACCESS_CAR_PROJECTION_STATUS"/>
+        <permission name="android.car.permission.CAR_CONTROL_AUDIO_SETTINGS"/>
+        <permission name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME"/>
+        <permission name="android.car.permission.CAR_DIAGNOSTICS"/>
+        <permission name="android.car.permission.CAR_DISPLAY_IN_CLUSTER"/>
+        <permission name="android.car.permission.CAR_DRIVING_STATE"/>
+        <permission name="android.car.permission.CAR_DYNAMICS_STATE"/>
+        <permission name="android.car.permission.CAR_EXTERIOR_LIGHTS"/>
+        <permission name="android.car.permission.CAR_IDENTIFICATION"/>
+        <permission name="android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL"/>
+        <permission name="android.car.permission.CAR_MILEAGE"/>
+        <permission name="android.car.permission.CAR_MOCK_VEHICLE_HAL"/>
+        <permission name="android.car.permission.CAR_NAVIGATION_MANAGER"/>
+        <permission name="android.car.permission.CAR_POWER"/>
+        <permission name="android.car.permission.CAR_PROJECTION"/>
+        <permission name="android.car.permission.CAR_TIRES"/>
+        <permission name="android.car.permission.CAR_TEST_SERVICE"/>
+        <permission name="android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION"/>
+        <permission name="android.car.permission.CAR_VENDOR_EXTENSION"/>
+        <permission name="android.car.permission.CONTROL_CAR_CLIMATE"/>
+        <permission name="android.car.permission.CONTROL_CAR_DOORS"/>
+        <permission name="android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS"/>
+        <permission name="android.car.permission.CONTROL_CAR_FEATURES"/>
+        <permission name="android.car.permission.CONTROL_CAR_MIRRORS"/>
+        <permission name="android.car.permission.CONTROL_CAR_SEATS"/>
+        <permission name="android.car.permission.CONTROL_CAR_WINDOWS"/>
+        <permission name="android.car.permission.GET_CAR_VENDOR_CATEGORY_INFO"/>
+        <permission name="android.car.permission.GET_CAR_VENDOR_CATEGORY_SEAT"/>
+        <permission name="android.car.permission.READ_CAR_STEERING"/>
+        <permission name="android.car.permission.SET_CAR_VENDOR_CATEGORY_INFO"/>
+        <permission name="android.car.permission.STORAGE_MONITORING"/>
+        <permission name="android.car.permission.VMS_PUBLISHER"/>
+        <permission name="android.car.permission.VMS_SUBSCRIBER"/>
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index 3d964fb..f2a33de 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -70,5 +70,6 @@
         <permission name="android.permission.READ_WIFI_CREDENTIAL" />
         <permission name="android.permission.USE_BACKGROUND_BLUR" />
         <permission name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS" />
+        <permission name="android.permission.FORCE_STOP_PACKAGES" />
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 8fd5d80..fae89d6 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -68,6 +68,11 @@
         <permission name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
     </privapp-permissions>
 
+    <privapp-permissions package="com.android.imsserviceentitlement">
+        <permission name="android.permission.MODIFY_PHONE_STATE" />
+        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
+    </privapp-permissions>
+
     <privapp-permissions package="com.android.launcher3">
         <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
     </privapp-permissions>
@@ -251,6 +256,7 @@
         <!-- Permissions required for reading DeviceConfig -->
         <permission name="android.permission.READ_DEVICE_CONFIG" />
         <permission name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"/>
+        <permission name="android.permission.MODIFY_QUIET_MODE"/>
     </privapp-permissions>
 
     <privapp-permissions package="com.android.providers.telephony">
@@ -406,8 +412,6 @@
         <permission name="android.permission.SET_WALLPAPER" />
         <permission name="android.permission.SET_WALLPAPER_COMPONENT" />
         <permission name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" />
-        <!-- Permissions required for Incremental CTS tests -->
-        <permission name="com.android.permission.USE_INSTALLER_V2"/>
         <permission name="android.permission.LOADER_USAGE_STATS"/>
         <!-- Permission required to test system only camera devices. -->
         <permission name="android.permission.SYSTEM_CAMERA" />
@@ -480,6 +484,8 @@
         <permission name="android.permission.SIGNAL_REBOOT_READINESS" />
         <!-- Permission required for CTS test - PeopleManagerTest -->
         <permission name="android.permission.READ_PEOPLE_DATA" />
+        <!-- Permission required for CTS test - UiTranslationManagerTest -->
+        <permission name="android.permission.MANAGE_UI_TRANSLATION" />
     </privapp-permissions>
 
     <privapp-permissions package="com.android.statementservice">
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 2db4c5d..66b8eae 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -223,7 +223,7 @@
     <alias name="sans-serif-condensed-medium" to="sans-serif-condensed" weight="500" />
 
     <family name="serif">
-        <font weight="400" style="normal">NotoSerif-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSerif.ttf</font>
         <font weight="700" style="normal">NotoSerif-Bold.ttf</font>
         <font weight="400" style="italic">NotoSerif-Italic.ttf</font>
         <font weight="700" style="italic">NotoSerif-BoldItalic.ttf</font>
@@ -245,7 +245,7 @@
     <alias name="monaco" to="monospace" />
 
     <family name="serif-monospace">
-        <font weight="400" style="normal">CutiveMono.ttf</font>
+        <font weight="400" style="normal">CutiveMono-Regular.ttf</font>
     </family>
     <alias name="courier" to="serif-monospace" />
     <alias name="courier new" to="serif-monospace" />
@@ -255,7 +255,7 @@
     </family>
 
     <family name="cursive">
-        <font weight="400" style="normal">DancingScript-Regular.ttf</font>
+        <font weight="400" style="normal">DancingScript.ttf</font>
         <font weight="700" style="normal">DancingScript-Bold.ttf</font>
     </family>
 
@@ -275,144 +275,144 @@
 
     <!-- fallback fonts -->
     <family lang="und-Arab" variant="elegant">
-        <font weight="400" style="normal">NotoNaskhArabic-Regular.ttf</font>
+        <font weight="400" style="normal">NotoNaskhArabic.ttf</font>
         <font weight="700" style="normal">NotoNaskhArabic-Bold.ttf</font>
     </family>
     <family lang="und-Arab" variant="compact">
-        <font weight="400" style="normal">NotoNaskhArabicUI-Regular.ttf</font>
+        <font weight="400" style="normal">NotoNaskhArabicUI.ttf</font>
         <font weight="700" style="normal">NotoNaskhArabicUI-Bold.ttf</font>
     </family>
     <family lang="und-Ethi">
-	      <font weight="400" style="normal">NotoSansEthiopic-VF.ttf
+	      <font weight="400" style="normal">NotoSansEthiopic-Regular.ttf
 	          <axis tag="wght" stylevalue="400"/>
 	      </font>
-	      <font weight="500" style="normal">NotoSansEthiopic-VF.ttf
+	      <font weight="500" style="normal">NotoSansEthiopic-Regular.ttf
 	          <axis tag="wght" stylevalue="500"/>
 	      </font>
-	      <font weight="600" style="normal">NotoSansEthiopic-VF.ttf
+	      <font weight="600" style="normal">NotoSansEthiopic-Regular.ttf
 	          <axis tag="wght" stylevalue="600"/>
 	      </font>
-	      <font weight="700" style="normal">NotoSansEthiopic-VF.ttf
+	      <font weight="700" style="normal">NotoSansEthiopic-Regular.ttf
 	          <axis tag="wght" stylevalue="700"/>
 	      </font>
-	      <font weight="400" style="normal" fallbackFor="serif">NotoSerifEthiopic-VF.ttf
+	      <font weight="400" style="normal" fallbackFor="serif">NotoSerifEthiopic-Regular.ttf
 	          <axis tag="wght" stylevalue="400"/>
 	      </font>
-	      <font weight="500" style="normal" fallbackFor="serif">NotoSerifEthiopic-VF.ttf
+	      <font weight="500" style="normal" fallbackFor="serif">NotoSerifEthiopic-Regular.ttf
 	          <axis tag="wght" stylevalue="500"/>
 	      </font>
-	      <font weight="600" style="normal" fallbackFor="serif">NotoSerifEthiopic-VF.ttf
+	      <font weight="600" style="normal" fallbackFor="serif">NotoSerifEthiopic-Regular.ttf
 	          <axis tag="wght" stylevalue="600"/>
 	      </font>
-	      <font weight="700" style="normal" fallbackFor="serif">NotoSerifEthiopic-VF.ttf
+	      <font weight="700" style="normal" fallbackFor="serif">NotoSerifEthiopic-Regular.ttf
 	          <axis tag="wght" stylevalue="700"/>
 	      </font>
     </family>
     <family lang="und-Hebr">
-        <font weight="400" style="normal">NotoSansHebrew-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansHebrew.ttf</font>
         <font weight="700" style="normal">NotoSansHebrew-Bold.ttf</font>
         <font weight="400" style="normal" fallbackFor="serif">NotoSerifHebrew-Regular.ttf</font>
         <font weight="700" style="normal" fallbackFor="serif">NotoSerifHebrew-Bold.ttf</font>
     </family>
     <family lang="und-Thai" variant="elegant">
-        <font weight="400" style="normal">NotoSansThai-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansThai.ttf</font>
         <font weight="700" style="normal">NotoSansThai-Bold.ttf</font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifThai-Regular.ttf</font>
+        <font weight="400" style="normal" fallbackFor="serif">NotoSerifThai.ttf</font>
         <font weight="700" style="normal" fallbackFor="serif">NotoSerifThai-Bold.ttf</font>
     </family>
     <family lang="und-Thai" variant="compact">
-        <font weight="400" style="normal">NotoSansThaiUI-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansThaiUI.ttf</font>
         <font weight="700" style="normal">NotoSansThaiUI-Bold.ttf</font>
     </family>
     <family lang="und-Armn">
-        <font weight="400" style="normal">NotoSansArmenian-VF.ttf
+        <font weight="400" style="normal">NotoSansArmenian-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSansArmenian-VF.ttf
+        <font weight="500" style="normal">NotoSansArmenian-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSansArmenian-VF.ttf
+        <font weight="600" style="normal">NotoSansArmenian-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSansArmenian-VF.ttf
+        <font weight="700" style="normal">NotoSansArmenian-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifArmenian-VF.ttf
+        <font weight="400" style="normal" fallbackFor="serif">NotoSerifArmenian-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal" fallbackFor="serif">NotoSerifArmenian-VF.ttf
+        <font weight="500" style="normal" fallbackFor="serif">NotoSerifArmenian-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal" fallbackFor="serif">NotoSerifArmenian-VF.ttf
+        <font weight="600" style="normal" fallbackFor="serif">NotoSerifArmenian-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifArmenian-VF.ttf
+        <font weight="700" style="normal" fallbackFor="serif">NotoSerifArmenian-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
     <family lang="und-Geor,und-Geok">
-        <font weight="400" style="normal">NotoSansGeorgian-VF.ttf
+        <font weight="400" style="normal">NotoSansGeorgian-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSansGeorgian-VF.ttf
+        <font weight="500" style="normal">NotoSansGeorgian-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSansGeorgian-VF.ttf
+        <font weight="600" style="normal">NotoSansGeorgian-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSansGeorgian-VF.ttf
+        <font weight="700" style="normal">NotoSansGeorgian-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifGeorgian-VF.ttf
+        <font weight="400" style="normal" fallbackFor="serif">NotoSerifGeorgian-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal" fallbackFor="serif">NotoSerifGeorgian-VF.ttf
+        <font weight="500" style="normal" fallbackFor="serif">NotoSerifGeorgian-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal" fallbackFor="serif">NotoSerifGeorgian-VF.ttf
+        <font weight="600" style="normal" fallbackFor="serif">NotoSerifGeorgian-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifGeorgian-VF.ttf
+        <font weight="700" style="normal" fallbackFor="serif">NotoSerifGeorgian-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
     <family lang="und-Deva" variant="elegant">
-        <font weight="400" style="normal">NotoSansDevanagari-VF.ttf
+        <font weight="400" style="normal">NotoSansDevanagari-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSansDevanagari-VF.ttf
+        <font weight="500" style="normal">NotoSansDevanagari-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSansDevanagari-VF.ttf
+        <font weight="600" style="normal">NotoSansDevanagari-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSansDevanagari-VF.ttf
+        <font weight="700" style="normal">NotoSansDevanagari-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifDevanagari-VF.ttf
+        <font weight="400" style="normal" fallbackFor="serif">NotoSerifDevanagari-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal" fallbackFor="serif">NotoSerifDevanagari-VF.ttf
+        <font weight="500" style="normal" fallbackFor="serif">NotoSerifDevanagari-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal" fallbackFor="serif">NotoSerifDevanagari-VF.ttf
+        <font weight="600" style="normal" fallbackFor="serif">NotoSerifDevanagari-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifDevanagari-VF.ttf
+        <font weight="700" style="normal" fallbackFor="serif">NotoSerifDevanagari-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
     <family lang="und-Deva" variant="compact">
-        <font weight="400" style="normal">NotoSansDevanagariUI-VF.ttf
+        <font weight="400" style="normal">NotoSansDevanagariUI-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSansDevanagariUI-VF.ttf
+        <font weight="500" style="normal">NotoSansDevanagariUI-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSansDevanagariUI-VF.ttf
+        <font weight="600" style="normal">NotoSansDevanagariUI-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSansDevanagariUI-VF.ttf
+        <font weight="700" style="normal">NotoSansDevanagariUI-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
@@ -421,347 +421,347 @@
          danda characters.
     -->
     <family lang="und-Gujr" variant="elegant">
-        <font weight="400" style="normal">NotoSansGujarati-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansGujarati.ttf</font>
         <font weight="700" style="normal">NotoSansGujarati-Bold.ttf</font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifGujarati-VF.ttf
+        <font weight="400" style="normal" fallbackFor="serif">NotoSerifGujarati-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal" fallbackFor="serif">NotoSerifGujarati-VF.ttf
+        <font weight="500" style="normal" fallbackFor="serif">NotoSerifGujarati-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal" fallbackFor="serif">NotoSerifGujarati-VF.ttf
+        <font weight="600" style="normal" fallbackFor="serif">NotoSerifGujarati-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifGujarati-VF.ttf
+        <font weight="700" style="normal" fallbackFor="serif">NotoSerifGujarati-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
     <family lang="und-Gujr" variant="compact">
-        <font weight="400" style="normal">NotoSansGujaratiUI-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansGujaratiUI.ttf</font>
         <font weight="700" style="normal">NotoSansGujaratiUI-Bold.ttf</font>
     </family>
     <family lang="und-Guru" variant="elegant">
-        <font weight="400" style="normal">NotoSansGurmukhi-VF.ttf
+        <font weight="400" style="normal">NotoSansGurmukhi-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSansGurmukhi-VF.ttf
+        <font weight="500" style="normal">NotoSansGurmukhi-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSansGurmukhi-VF.ttf
+        <font weight="600" style="normal">NotoSansGurmukhi-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSansGurmukhi-VF.ttf
+        <font weight="700" style="normal">NotoSansGurmukhi-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifGurmukhi-VF.ttf
+        <font weight="400" style="normal" fallbackFor="serif">NotoSerifGurmukhi-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal" fallbackFor="serif">NotoSerifGurmukhi-VF.ttf
+        <font weight="500" style="normal" fallbackFor="serif">NotoSerifGurmukhi-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal" fallbackFor="serif">NotoSerifGurmukhi-VF.ttf
+        <font weight="600" style="normal" fallbackFor="serif">NotoSerifGurmukhi-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifGurmukhi-VF.ttf
+        <font weight="700" style="normal" fallbackFor="serif">NotoSerifGurmukhi-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
     <family lang="und-Guru" variant="compact">
-        <font weight="400" style="normal">NotoSansGurmukhiUI-VF.ttf
+        <font weight="400" style="normal">NotoSansGurmukhiUI-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSansGurmukhiUI-VF.ttf
+        <font weight="500" style="normal">NotoSansGurmukhiUI-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSansGurmukhiUI-VF.ttf
+        <font weight="600" style="normal">NotoSansGurmukhiUI-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSansGurmukhiUI-VF.ttf
+        <font weight="700" style="normal">NotoSansGurmukhiUI-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
     <family lang="und-Taml" variant="elegant">
-        <font weight="400" style="normal">NotoSansTamil-VF.ttf
+        <font weight="400" style="normal">NotoSansTamil-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSansTamil-VF.ttf
+        <font weight="500" style="normal">NotoSansTamil-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSansTamil-VF.ttf
+        <font weight="600" style="normal">NotoSansTamil-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSansTamil-VF.ttf
+        <font weight="700" style="normal">NotoSansTamil-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifTamil-VF.ttf
+        <font weight="400" style="normal" fallbackFor="serif">NotoSerifTamil-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal" fallbackFor="serif">NotoSerifTamil-VF.ttf
+        <font weight="500" style="normal" fallbackFor="serif">NotoSerifTamil-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal" fallbackFor="serif">NotoSerifTamil-VF.ttf
+        <font weight="600" style="normal" fallbackFor="serif">NotoSerifTamil-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifTamil-VF.ttf
+        <font weight="700" style="normal" fallbackFor="serif">NotoSerifTamil-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
     <family lang="und-Taml" variant="compact">
-        <font weight="400" style="normal">NotoSansTamilUI-VF.ttf
+        <font weight="400" style="normal">NotoSansTamilUI-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSansTamilUI-VF.ttf
+        <font weight="500" style="normal">NotoSansTamilUI-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSansTamilUI-VF.ttf
+        <font weight="600" style="normal">NotoSansTamilUI-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSansTamilUI-VF.ttf
+        <font weight="700" style="normal">NotoSansTamilUI-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
     <family lang="und-Mlym" variant="elegant">
-        <font weight="400" style="normal">NotoSansMalayalam-VF.ttf
+        <font weight="400" style="normal">NotoSansMalayalam-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSansMalayalam-VF.ttf
+        <font weight="500" style="normal">NotoSansMalayalam-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSansMalayalam-VF.ttf
+        <font weight="600" style="normal">NotoSansMalayalam-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSansMalayalam-VF.ttf
+        <font weight="700" style="normal">NotoSansMalayalam-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifMalayalam-VF.ttf
+        <font weight="400" style="normal" fallbackFor="serif">NotoSerifMalayalam-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal" fallbackFor="serif">NotoSerifMalayalam-VF.ttf
+        <font weight="500" style="normal" fallbackFor="serif">NotoSerifMalayalam-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal" fallbackFor="serif">NotoSerifMalayalam-VF.ttf
+        <font weight="600" style="normal" fallbackFor="serif">NotoSerifMalayalam-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifMalayalam-VF.ttf
+        <font weight="700" style="normal" fallbackFor="serif">NotoSerifMalayalam-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
     <family lang="und-Mlym" variant="compact">
-        <font weight="400" style="normal">NotoSansMalayalamUI-VF.ttf
+        <font weight="400" style="normal">NotoSansMalayalamUI-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSansMalayalamUI-VF.ttf
+        <font weight="500" style="normal">NotoSansMalayalamUI-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSansMalayalamUI-VF.ttf
+        <font weight="600" style="normal">NotoSansMalayalamUI-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSansMalayalamUI-VF.ttf
+        <font weight="700" style="normal">NotoSansMalayalamUI-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
     <family lang="und-Beng" variant="elegant">
-        <font weight="400" style="normal">NotoSansBengali-VF.ttf
+        <font weight="400" style="normal">NotoSansBengali-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSansBengali-VF.ttf
+        <font weight="500" style="normal">NotoSansBengali-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSansBengali-VF.ttf
+        <font weight="600" style="normal">NotoSansBengali-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSansBengali-VF.ttf
+        <font weight="700" style="normal">NotoSansBengali-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifBengali-VF.ttf
+        <font weight="400" style="normal" fallbackFor="serif">NotoSerifBengali-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal" fallbackFor="serif">NotoSerifBengali-VF.ttf
+        <font weight="500" style="normal" fallbackFor="serif">NotoSerifBengali-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal" fallbackFor="serif">NotoSerifBengali-VF.ttf
+        <font weight="600" style="normal" fallbackFor="serif">NotoSerifBengali-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifBengali-VF.ttf
+        <font weight="700" style="normal" fallbackFor="serif">NotoSerifBengali-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
     <family lang="und-Beng" variant="compact">
-        <font weight="400" style="normal">NotoSansBengaliUI-VF.ttf
+        <font weight="400" style="normal">NotoSansBengaliUI-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSansBengaliUI-VF.ttf
+        <font weight="500" style="normal">NotoSansBengaliUI-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSansBengaliUI-VF.ttf
+        <font weight="600" style="normal">NotoSansBengaliUI-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSansBengaliUI-VF.ttf
+        <font weight="700" style="normal">NotoSansBengaliUI-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
     <family lang="und-Telu" variant="elegant">
-        <font weight="400" style="normal">NotoSansTelugu-VF.ttf
+        <font weight="400" style="normal">NotoSansTelugu-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSansTelugu-VF.ttf
+        <font weight="500" style="normal">NotoSansTelugu-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSansTelugu-VF.ttf
+        <font weight="600" style="normal">NotoSansTelugu-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSansTelugu-VF.ttf
+        <font weight="700" style="normal">NotoSansTelugu-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifTelugu-VF.ttf
+        <font weight="400" style="normal" fallbackFor="serif">NotoSerifTelugu-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal" fallbackFor="serif">NotoSerifTelugu-VF.ttf
+        <font weight="500" style="normal" fallbackFor="serif">NotoSerifTelugu-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal" fallbackFor="serif">NotoSerifTelugu-VF.ttf
+        <font weight="600" style="normal" fallbackFor="serif">NotoSerifTelugu-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifTelugu-VF.ttf
+        <font weight="700" style="normal" fallbackFor="serif">NotoSerifTelugu-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
     <family lang="und-Telu" variant="compact">
-        <font weight="400" style="normal">NotoSansTeluguUI-VF.ttf
+        <font weight="400" style="normal">NotoSansTeluguUI-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSansTeluguUI-VF.ttf
+        <font weight="500" style="normal">NotoSansTeluguUI-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSansTeluguUI-VF.ttf
+        <font weight="600" style="normal">NotoSansTeluguUI-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSansTeluguUI-VF.ttf
+        <font weight="700" style="normal">NotoSansTeluguUI-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
     <family lang="und-Knda" variant="elegant">
-        <font weight="400" style="normal">NotoSansKannada-VF.ttf
+        <font weight="400" style="normal">NotoSansKannada-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSansKannada-VF.ttf
+        <font weight="500" style="normal">NotoSansKannada-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSansKannada-VF.ttf
+        <font weight="600" style="normal">NotoSansKannada-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSansKannada-VF.ttf
+        <font weight="700" style="normal">NotoSansKannada-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifKannada-VF.ttf
+        <font weight="400" style="normal" fallbackFor="serif">NotoSerifKannada-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal" fallbackFor="serif">NotoSerifKannada-VF.ttf
+        <font weight="500" style="normal" fallbackFor="serif">NotoSerifKannada-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal" fallbackFor="serif">NotoSerifKannada-VF.ttf
+        <font weight="600" style="normal" fallbackFor="serif">NotoSerifKannada-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifKannada-VF.ttf
+        <font weight="700" style="normal" fallbackFor="serif">NotoSerifKannada-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
     <family lang="und-Knda" variant="compact">
-        <font weight="400" style="normal">NotoSansKannadaUI-VF.ttf
+        <font weight="400" style="normal">NotoSansKannadaUI-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSansKannadaUI-VF.ttf
+        <font weight="500" style="normal">NotoSansKannadaUI-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSansKannadaUI-VF.ttf
+        <font weight="600" style="normal">NotoSansKannadaUI-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSansKannadaUI-VF.ttf
+        <font weight="700" style="normal">NotoSansKannadaUI-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
     <family lang="und-Orya" variant="elegant">
-        <font weight="400" style="normal">NotoSansOriya-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansOriya.ttf</font>
         <font weight="700" style="normal">NotoSansOriya-Bold.ttf</font>
     </family>
     <family lang="und-Orya" variant="compact">
-        <font weight="400" style="normal">NotoSansOriyaUI-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansOriyaUI.ttf</font>
         <font weight="700" style="normal">NotoSansOriyaUI-Bold.ttf</font>
     </family>
     <family lang="und-Sinh" variant="elegant">
-        <font weight="400" style="normal">NotoSansSinhala-VF.ttf
+        <font weight="400" style="normal">NotoSansSinhala-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSansSinhala-VF.ttf
+        <font weight="500" style="normal">NotoSansSinhala-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSansSinhala-VF.ttf
+        <font weight="600" style="normal">NotoSansSinhala-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSansSinhala-VF.ttf
+        <font weight="700" style="normal">NotoSansSinhala-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifSinhala-VF.ttf
+        <font weight="400" style="normal" fallbackFor="serif">NotoSerifSinhala-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal" fallbackFor="serif">NotoSerifSinhala-VF.ttf
+        <font weight="500" style="normal" fallbackFor="serif">NotoSerifSinhala-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal" fallbackFor="serif">NotoSerifSinhala-VF.ttf
+        <font weight="600" style="normal" fallbackFor="serif">NotoSerifSinhala-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal" fallbackFor="serif">NotoSerifSinhala-VF.ttf
+        <font weight="700" style="normal" fallbackFor="serif">NotoSerifSinhala-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
     <family lang="und-Sinh" variant="compact">
-        <font weight="400" style="normal">NotoSansSinhalaUI-VF.ttf
+        <font weight="400" style="normal">NotoSansSinhalaUI-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSansSinhalaUI-VF.ttf
+        <font weight="500" style="normal">NotoSansSinhalaUI-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSansSinhalaUI-VF.ttf
+        <font weight="600" style="normal">NotoSansSinhalaUI-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSansSinhalaUI-VF.ttf
+        <font weight="700" style="normal">NotoSansSinhalaUI-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
     <family lang="und-Khmr" variant="elegant">
-        <font weight="100" style="normal">NotoSansKhmer-VF.ttf
+        <font weight="100" style="normal">NotoSansKhmer-Regular.ttf
             <axis tag="wdth" stylevalue="100.0"/>
             <axis tag="wght" stylevalue="26.0"/>
         </font>
-        <font weight="200" style="normal">NotoSansKhmer-VF.ttf
+        <font weight="200" style="normal">NotoSansKhmer-Regular.ttf
             <axis tag="wdth" stylevalue="100.0"/>
             <axis tag="wght" stylevalue="39.0"/>
         </font>
-        <font weight="300" style="normal">NotoSansKhmer-VF.ttf
+        <font weight="300" style="normal">NotoSansKhmer-Regular.ttf
             <axis tag="wdth" stylevalue="100.0"/>
             <axis tag="wght" stylevalue="58.0"/>
         </font>
-        <font weight="400" style="normal">NotoSansKhmer-VF.ttf
+        <font weight="400" style="normal">NotoSansKhmer-Regular.ttf
             <axis tag="wdth" stylevalue="100.0"/>
             <axis tag="wght" stylevalue="90.0"/>
         </font>
-        <font weight="500" style="normal">NotoSansKhmer-VF.ttf
+        <font weight="500" style="normal">NotoSansKhmer-Regular.ttf
             <axis tag="wdth" stylevalue="100.0"/>
             <axis tag="wght" stylevalue="108.0"/>
         </font>
-        <font weight="600" style="normal">NotoSansKhmer-VF.ttf
+        <font weight="600" style="normal">NotoSansKhmer-Regular.ttf
             <axis tag="wdth" stylevalue="100.0"/>
             <axis tag="wght" stylevalue="128.0"/>
         </font>
-        <font weight="700" style="normal">NotoSansKhmer-VF.ttf
+        <font weight="700" style="normal">NotoSansKhmer-Regular.ttf
             <axis tag="wdth" stylevalue="100.0"/>
             <axis tag="wght" stylevalue="151.0"/>
         </font>
-        <font weight="800" style="normal">NotoSansKhmer-VF.ttf
+        <font weight="800" style="normal">NotoSansKhmer-Regular.ttf
             <axis tag="wdth" stylevalue="100.0"/>
             <axis tag="wght" stylevalue="169.0"/>
         </font>
-        <font weight="900" style="normal">NotoSansKhmer-VF.ttf
+        <font weight="900" style="normal">NotoSansKhmer-Regular.ttf
             <axis tag="wdth" stylevalue="100.0"/>
             <axis tag="wght" stylevalue="190.0"/>
         </font>
@@ -769,17 +769,17 @@
         <font weight="700" style="normal" fallbackFor="serif">NotoSerifKhmer-Bold.otf</font>
     </family>
     <family lang="und-Khmr" variant="compact">
-        <font weight="400" style="normal">NotoSansKhmerUI-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansKhmerUI.ttf</font>
         <font weight="700" style="normal">NotoSansKhmerUI-Bold.ttf</font>
     </family>
     <family lang="und-Laoo" variant="elegant">
-        <font weight="400" style="normal">NotoSansLao-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansLao.ttf</font>
         <font weight="700" style="normal">NotoSansLao-Bold.ttf</font>
-        <font weight="400" style="normal" fallbackFor="serif">NotoSerifLao-Regular.ttf</font>
+        <font weight="400" style="normal" fallbackFor="serif">NotoSerifLao.ttf</font>
         <font weight="700" style="normal" fallbackFor="serif">NotoSerifLao-Bold.ttf</font>
     </family>
     <family lang="und-Laoo" variant="compact">
-        <font weight="400" style="normal">NotoSansLaoUI-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansLaoUI.ttf</font>
         <font weight="700" style="normal">NotoSansLaoUI-Bold.ttf</font>
     </family>
     <family lang="und-Mymr" variant="elegant">
@@ -795,56 +795,56 @@
         <font weight="700" style="normal">NotoSansMyanmarUI-Bold.otf</font>
     </family>
     <family lang="und-Thaa">
-        <font weight="400" style="normal">NotoSansThaana-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansThaana.ttf</font>
         <font weight="700" style="normal">NotoSansThaana-Bold.ttf</font>
     </family>
     <family lang="und-Cham">
-        <font weight="400" style="normal">NotoSansCham-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansCham.ttf</font>
         <font weight="700" style="normal">NotoSansCham-Bold.ttf</font>
     </family>
     <family lang="und-Ahom">
         <font weight="400" style="normal">NotoSansAhom-Regular.otf</font>
     </family>
     <family lang="und-Adlm">
-        <font weight="400" style="normal">NotoSansAdlam-VF.ttf
+        <font weight="400" style="normal">NotoSansAdlam-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSansAdlam-VF.ttf
+        <font weight="500" style="normal">NotoSansAdlam-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSansAdlam-VF.ttf
+        <font weight="600" style="normal">NotoSansAdlam-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSansAdlam-VF.ttf
+        <font weight="700" style="normal">NotoSansAdlam-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
     <family lang="und-Avst">
-        <font weight="400" style="normal">NotoSansAvestan-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansAvestan.ttf</font>
     </family>
     <family lang="und-Bali">
-        <font weight="400" style="normal">NotoSansBalinese-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansBalinese.ttf</font>
     </family>
     <family lang="und-Bamu">
-        <font weight="400" style="normal">NotoSansBamum-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansBamum.ttf</font>
     </family>
     <family lang="und-Batk">
-        <font weight="400" style="normal">NotoSansBatak-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansBatak.ttf</font>
     </family>
     <family lang="und-Brah">
-        <font weight="400" style="normal">NotoSansBrahmi-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansBrahmi.ttf</font>
     </family>
     <family lang="und-Bugi">
-        <font weight="400" style="normal">NotoSansBuginese-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansBuginese.ttf</font>
     </family>
     <family lang="und-Buhd">
-        <font weight="400" style="normal">NotoSansBuhid-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansBuhid.ttf</font>
     </family>
     <family lang="und-Cans">
-        <font weight="400" style="normal">NotoSansCanadianAboriginal-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansCanadianAboriginal.ttf</font>
     </family>
     <family lang="und-Cari">
-        <font weight="400" style="normal">NotoSansCarian-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansCarian.ttf</font>
     </family>
     <family lang="und-Cakm">
         <font weight="400" style="normal">NotoSansChakma-Regular.otf</font>
@@ -853,164 +853,164 @@
         <font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font>
     </family>
     <family lang="und-Copt">
-        <font weight="400" style="normal">NotoSansCoptic-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansCoptic.ttf</font>
     </family>
     <family lang="und-Xsux">
-        <font weight="400" style="normal">NotoSansCuneiform-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansCuneiform.ttf</font>
     </family>
     <family lang="und-Cprt">
-        <font weight="400" style="normal">NotoSansCypriot-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansCypriot.ttf</font>
     </family>
     <family lang="und-Dsrt">
-        <font weight="400" style="normal">NotoSansDeseret-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansDeseret.ttf</font>
     </family>
     <family lang="und-Egyp">
-        <font weight="400" style="normal">NotoSansEgyptianHieroglyphs-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansEgyptianHieroglyphs.ttf</font>
     </family>
     <family lang="und-Elba">
         <font weight="400" style="normal">NotoSansElbasan-Regular.otf</font>
     </family>
     <family lang="und-Glag">
-        <font weight="400" style="normal">NotoSansGlagolitic-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansGlagolitic.ttf</font>
     </family>
     <family lang="und-Goth">
-        <font weight="400" style="normal">NotoSansGothic-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansGothic.ttf</font>
     </family>
     <family lang="und-Hano">
-        <font weight="400" style="normal">NotoSansHanunoo-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansHanunoo.ttf</font>
     </family>
     <family lang="und-Armi">
-        <font weight="400" style="normal">NotoSansImperialAramaic-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansImperialAramaic.ttf</font>
     </family>
     <family lang="und-Phli">
-        <font weight="400" style="normal">NotoSansInscriptionalPahlavi-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansInscriptionalPahlavi.ttf</font>
     </family>
     <family lang="und-Prti">
-        <font weight="400" style="normal">NotoSansInscriptionalParthian-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansInscriptionalParthian.ttf</font>
     </family>
     <family lang="und-Java">
         <font weight="400" style="normal">NotoSansJavanese-Regular.otf</font>
     </family>
     <family lang="und-Kthi">
-        <font weight="400" style="normal">NotoSansKaithi-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansKaithi.ttf</font>
     </family>
     <family lang="und-Kali">
-        <font weight="400" style="normal">NotoSansKayahLi-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansKayahLi.ttf</font>
     </family>
     <family lang="und-Khar">
-        <font weight="400" style="normal">NotoSansKharoshthi-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansKharoshthi.ttf</font>
     </family>
     <family lang="und-Lepc">
-        <font weight="400" style="normal">NotoSansLepcha-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansLepcha.ttf</font>
     </family>
     <family lang="und-Limb">
-        <font weight="400" style="normal">NotoSansLimbu-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansLimbu.ttf</font>
     </family>
     <family lang="und-Linb">
-        <font weight="400" style="normal">NotoSansLinearB-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansLinearB.ttf</font>
     </family>
     <family lang="und-Lisu">
-        <font weight="400" style="normal">NotoSansLisu-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansLisu.ttf</font>
     </family>
     <family lang="und-Lyci">
-        <font weight="400" style="normal">NotoSansLycian-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansLycian.ttf</font>
     </family>
     <family lang="und-Lydi">
-        <font weight="400" style="normal">NotoSansLydian-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansLydian.ttf</font>
     </family>
     <family lang="und-Mand">
-        <font weight="400" style="normal">NotoSansMandaic-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansMandaic.ttf</font>
     </family>
     <family lang="und-Mtei">
-        <font weight="400" style="normal">NotoSansMeeteiMayek-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansMeeteiMayek.ttf</font>
     </family>
     <family lang="und-Talu">
-        <font weight="400" style="normal">NotoSansNewTaiLue-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansNewTaiLue.ttf</font>
     </family>
     <family lang="und-Nkoo">
-        <font weight="400" style="normal">NotoSansNKo-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansNKo.ttf</font>
     </family>
     <family lang="und-Ogam">
-        <font weight="400" style="normal">NotoSansOgham-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansOgham.ttf</font>
     </family>
     <family lang="und-Olck">
-        <font weight="400" style="normal">NotoSansOlChiki-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansOlChiki.ttf</font>
     </family>
     <family lang="und-Ital">
-        <font weight="400" style="normal">NotoSansOldItalic-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansOldItalic.ttf</font>
     </family>
     <family lang="und-Xpeo">
-        <font weight="400" style="normal">NotoSansOldPersian-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansOldPersian.ttf</font>
     </family>
     <family lang="und-Sarb">
-        <font weight="400" style="normal">NotoSansOldSouthArabian-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansOldSouthArabian.ttf</font>
     </family>
     <family lang="und-Orkh">
-        <font weight="400" style="normal">NotoSansOldTurkic-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansOldTurkic.ttf</font>
     </family>
     <family lang="und-Osge">
         <font weight="400" style="normal">NotoSansOsage-Regular.ttf</font>
     </family>
     <family lang="und-Osma">
-        <font weight="400" style="normal">NotoSansOsmanya-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansOsmanya.ttf</font>
     </family>
     <family lang="und-Phnx">
-        <font weight="400" style="normal">NotoSansPhoenician-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansPhoenician.ttf</font>
     </family>
     <family lang="und-Rjng">
-        <font weight="400" style="normal">NotoSansRejang-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansRejang.ttf</font>
     </family>
     <family lang="und-Runr">
-        <font weight="400" style="normal">NotoSansRunic-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansRunic.ttf</font>
     </family>
     <family lang="und-Samr">
-        <font weight="400" style="normal">NotoSansSamaritan-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansSamaritan.ttf</font>
     </family>
     <family lang="und-Saur">
-        <font weight="400" style="normal">NotoSansSaurashtra-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansSaurashtra.ttf</font>
     </family>
     <family lang="und-Shaw">
-        <font weight="400" style="normal">NotoSansShavian-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansShavian.ttf</font>
     </family>
     <family lang="und-Sund">
-        <font weight="400" style="normal">NotoSansSundanese-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansSundanese.ttf</font>
     </family>
     <family lang="und-Sylo">
-        <font weight="400" style="normal">NotoSansSylotiNagri-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansSylotiNagri.ttf</font>
     </family>
     <!-- Esrangela should precede Eastern and Western Syriac, since it's our default form. -->
     <family lang="und-Syre">
-        <font weight="400" style="normal">NotoSansSyriacEstrangela-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansSyriacEstrangela.ttf</font>
     </family>
     <family lang="und-Syrn">
-        <font weight="400" style="normal">NotoSansSyriacEastern-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansSyriacEastern.ttf</font>
     </family>
     <family lang="und-Syrj">
-        <font weight="400" style="normal">NotoSansSyriacWestern-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansSyriacWestern.ttf</font>
     </family>
     <family lang="und-Tglg">
-        <font weight="400" style="normal">NotoSansTagalog-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansTagalog.ttf</font>
     </family>
     <family lang="und-Tagb">
-        <font weight="400" style="normal">NotoSansTagbanwa-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansTagbanwa.ttf</font>
     </family>
     <family lang="und-Lana">
-        <font weight="400" style="normal">NotoSansTaiTham-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansTaiTham.ttf</font>
     </family>
     <family lang="und-Tavt">
-        <font weight="400" style="normal">NotoSansTaiViet-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansTaiViet.ttf</font>
     </family>
     <family lang="und-Tibt">
-        <font weight="400" style="normal">NotoSerifTibetan-VF.ttf
+        <font weight="400" style="normal">NotoSerifTibetan-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSerifTibetan-VF.ttf
+        <font weight="500" style="normal">NotoSerifTibetan-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSerifTibetan-VF.ttf
+        <font weight="600" style="normal">NotoSerifTibetan-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSerifTibetan-VF.ttf
+        <font weight="700" style="normal">NotoSerifTibetan-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
@@ -1018,29 +1018,29 @@
         <font weight="400" style="normal">NotoSansTifinagh-Regular.otf</font>
     </family>
     <family lang="und-Ugar">
-        <font weight="400" style="normal">NotoSansUgaritic-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansUgaritic.ttf</font>
     </family>
     <family lang="und-Vaii">
-        <font weight="400" style="normal">NotoSansVai-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansVai.ttf</font>
     </family>
     <family>
         <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted.ttf</font>
     </family>
     <family lang="zh-Hans">
-        <font weight="400" style="normal" index="2">NotoSansCJK-Regular.ttc</font>
-        <font weight="400" style="normal" index="2" fallbackFor="serif">NotoSerifCJK-Regular.ttc</font>
+        <font weight="400" style="normal" index="2">NotoSansCJKjp-Regular.otc</font>
+        <font weight="400" style="normal" index="2" fallbackFor="serif">NotoSerifCJKjp-Regular.otc</font>
     </family>
     <family lang="zh-Hant,zh-Bopo">
-        <font weight="400" style="normal" index="3">NotoSansCJK-Regular.ttc</font>
-        <font weight="400" style="normal" index="3" fallbackFor="serif">NotoSerifCJK-Regular.ttc</font>
+        <font weight="400" style="normal" index="3">NotoSansCJKjp-Regular.otc</font>
+        <font weight="400" style="normal" index="3" fallbackFor="serif">NotoSerifCJKjp-Regular.otc</font>
     </family>
     <family lang="ja">
-        <font weight="400" style="normal" index="0">NotoSansCJK-Regular.ttc</font>
-        <font weight="400" style="normal" index="0" fallbackFor="serif">NotoSerifCJK-Regular.ttc</font>
+        <font weight="400" style="normal" index="0">NotoSansCJKjp-Regular.otc</font>
+        <font weight="400" style="normal" index="0" fallbackFor="serif">NotoSerifCJKjp-Regular.otc</font>
     </family>
     <family lang="ko">
-        <font weight="400" style="normal" index="1">NotoSansCJK-Regular.ttc</font>
-        <font weight="400" style="normal" index="1" fallbackFor="serif">NotoSerifCJK-Regular.ttc</font>
+        <font weight="400" style="normal" index="1">NotoSansCJKjp-Regular.otc</font>
+        <font weight="400" style="normal" index="1" fallbackFor="serif">NotoSerifCJKjp-Regular.otc</font>
     </family>
     <family lang="und-Zsye">
         <font weight="400" style="normal">NotoColorEmoji.ttf</font>
@@ -1053,16 +1053,16 @@
         override the East Asian punctuation for Chinese.
     -->
     <family lang="und-Tale">
-        <font weight="400" style="normal">NotoSansTaiLe-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansTaiLe.ttf</font>
     </family>
     <family lang="und-Yiii">
-        <font weight="400" style="normal">NotoSansYi-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansYi.ttf</font>
     </family>
     <family lang="und-Mong">
-        <font weight="400" style="normal">NotoSansMongolian-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansMongolian.ttf</font>
     </family>
     <family lang="und-Phag">
-        <font weight="400" style="normal">NotoSansPhagsPa-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansPhagsPa.ttf</font>
     </family>
     <family lang="und-Hluw">
         <font weight="400" style="normal">NotoSansAnatolianHieroglyphs-Regular.otf</font>
@@ -1152,72 +1152,72 @@
         <font weight="400" style="normal">NotoSerifDogra-Regular.ttf</font>
     </family>
     <family lang="und-Medf">
-        <font weight="400" style="normal">NotoSansMedefaidrin-VF.ttf
+        <font weight="400" style="normal">NotoSansMedefaidrin-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSansMedefaidrin-VF.ttf
+        <font weight="500" style="normal">NotoSansMedefaidrin-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSansMedefaidrin-VF.ttf
+        <font weight="600" style="normal">NotoSansMedefaidrin-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSansMedefaidrin-VF.ttf
+        <font weight="700" style="normal">NotoSansMedefaidrin-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
     <family lang="und-Soyo">
-        <font weight="400" style="normal">NotoSansSoyombo-VF.ttf
+        <font weight="400" style="normal">NotoSansSoyombo-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSansSoyombo-VF.ttf
+        <font weight="500" style="normal">NotoSansSoyombo-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSansSoyombo-VF.ttf
+        <font weight="600" style="normal">NotoSansSoyombo-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSansSoyombo-VF.ttf
+        <font weight="700" style="normal">NotoSansSoyombo-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
     <family lang="und-Takr">
-        <font weight="400" style="normal">NotoSansTakri-VF.ttf
+        <font weight="400" style="normal">NotoSansTakri-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSansTakri-VF.ttf
+        <font weight="500" style="normal">NotoSansTakri-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSansTakri-VF.ttf
+        <font weight="600" style="normal">NotoSansTakri-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSansTakri-VF.ttf
+        <font weight="700" style="normal">NotoSansTakri-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
     <family lang="und-Hmnp">
-        <font weight="400" style="normal">NotoSerifNyiakengPuachueHmong-VF.ttf
+        <font weight="400" style="normal">NotoSerifHmongNyiakeng-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSerifNyiakengPuachueHmong-VF.ttf
+        <font weight="500" style="normal">NotoSerifHmongNyiakeng-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSerifNyiakengPuachueHmong-VF.ttf
+        <font weight="600" style="normal">NotoSerifHmongNyiakeng-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSerifNyiakengPuachueHmong-VF.ttf
+        <font weight="700" style="normal">NotoSerifHmongNyiakeng-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
     <family lang="und-Yezi">
-        <font weight="400" style="normal">NotoSerifYezidi-VF.ttf
+        <font weight="400" style="normal">NotoSerifYezidi-Regular.ttf
             <axis tag="wght" stylevalue="400"/>
         </font>
-        <font weight="500" style="normal">NotoSerifYezidi-VF.ttf
+        <font weight="500" style="normal">NotoSerifYezidi-Regular.ttf
             <axis tag="wght" stylevalue="500"/>
         </font>
-        <font weight="600" style="normal">NotoSerifYezidi-VF.ttf
+        <font weight="600" style="normal">NotoSerifYezidi-Regular.ttf
             <axis tag="wght" stylevalue="600"/>
         </font>
-        <font weight="700" style="normal">NotoSerifYezidi-VF.ttf
+        <font weight="700" style="normal">NotoSerifYezidi-Regular.ttf
             <axis tag="wght" stylevalue="700"/>
         </font>
     </family>
diff --git a/graphics/java/android/graphics/FrameInfo.java b/graphics/java/android/graphics/FrameInfo.java
index d59abb5..189be53 100644
--- a/graphics/java/android/graphics/FrameInfo.java
+++ b/graphics/java/android/graphics/FrameInfo.java
@@ -69,28 +69,26 @@
     // animation & drawing system
     public static final int VSYNC = 3;
 
-    // The time of the oldest input event
-    public static final int OLDEST_INPUT_EVENT = 4;
-
-    // The time of the newest input event
-    public static final int NEWEST_INPUT_EVENT = 5;
+    // The id of the input event that caused the current frame
+    public static final int INPUT_EVENT_ID = 4;
 
     // When input event handling started
-    public static final int HANDLE_INPUT_START = 6;
+    public static final int HANDLE_INPUT_START = 5;
 
     // When animation evaluations started
-    public static final int ANIMATION_START = 7;
+    public static final int ANIMATION_START = 6;
 
     // When ViewRootImpl#performTraversals() started
-    public static final int PERFORM_TRAVERSALS_START = 8;
+    public static final int PERFORM_TRAVERSALS_START = 7;
 
     // When View:draw() started
-    public static final int DRAW_START = 9;
+    public static final int DRAW_START = 8;
 
     // When the frame needs to be ready by
-    public static final int FRAME_DEADLINE = 10;
+    public static final int FRAME_DEADLINE = 9;
 
     // Must be the last one
+    // This value must be in sync with `UI_THREAD_FRAME_INFO_SIZE` in FrameInfo.h
     private static final int FRAME_INFO_SIZE = FRAME_DEADLINE + 1;
 
     /** checkstyle */
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index f1f9a5f..e222570 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -153,6 +153,13 @@
      * resource bitmaps often are) the filtering will already have been
      * done.</p>
      *
+     * <p>On devices running {@link Build.VERSION_CODES#O} and below, hardware
+     * accelerated drawing always uses bilinear sampling on scaled bitmaps,
+     * regardless of this flag. On devices running {@link Build.VERSION_CODES#Q}
+     * and above, this flag defaults to being set on a new {@code Paint}. It can
+     * be cleared with {@link #setFlags} or {@link #setFilterBitmap}.</p>
+     *
+     * @see #Paint()
      * @see #Paint(int)
      * @see #setFlags(int)
      */
@@ -558,6 +565,12 @@
 
     /**
      * Create a new paint with default settings.
+     *
+     * <p>On devices running {@link Build.VERSION_CODES#O} and below, hardware
+     * 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>
      */
     public Paint() {
         this(0);
@@ -567,6 +580,13 @@
      * Create a new paint with the specified flags. Use setFlags() to change
      * these after the paint is created.
      *
+     * <p>On devices running {@link Build.VERSION_CODES#O} and below, hardware
+     * 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 always set by this constructor, regardless
+     * of the value of {@code flags}. It can be cleared with {@link #setFlags} or
+     * {@link #setFilterBitmap}.</p>
+     *
      * @param flags initial flag bits, as if they were passed via setFlags().
      */
     public Paint(int flags) {
@@ -991,6 +1011,7 @@
      * device pixels. That is dependent on dithering and xfermodes.
      *
      * @see #setFilterBitmap(boolean) setFilterBitmap()
+     * @see #FILTER_BITMAP_FLAG
      */
     public final boolean isFilterBitmap() {
         return (getFlags() & FILTER_BITMAP_FLAG) != 0;
@@ -1004,6 +1025,7 @@
      *
      * @param filter true to set the FILTER_BITMAP_FLAG bit in the paint's
      *               flags, false to clear it.
+     * @see #FILTER_BITMAP_FLAG
      */
     public void setFilterBitmap(boolean filter) {
         nSetFilterBitmap(mNativePaint, filter);
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 32c777c..c807882 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -172,9 +172,9 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public long native_instance;
+    public final long native_instance;
 
-    private Runnable mCleaner;
+    private final Runnable mCleaner;
 
     /** @hide */
     @IntDef(value = {NORMAL, BOLD, ITALIC, BOLD_ITALIC})
@@ -189,9 +189,9 @@
     /** @hide */ public static final int STYLE_MASK = 0x03;
 
     @UnsupportedAppUsage
-    private @Style int mStyle = 0;
+    private @Style final int mStyle;
 
-    private @IntRange(from = 0, to = FontStyle.FONT_WEIGHT_MAX) int mWeight = 0;
+    private @IntRange(from = 0, to = FontStyle.FONT_WEIGHT_MAX) final int mWeight;
 
     // Value for weight and italic. Indicates the value is resolved by font metadata.
     // Must be the same as the C++ constant in core/jni/android/graphics/FontFamily.cpp
@@ -207,6 +207,7 @@
     private static final int STYLE_NORMAL = 0;
     private static final int STYLE_ITALIC = 1;
 
+    @GuardedBy("this")
     private int[] mSupportedAxes;
     private static final int[] EMPTY_AXES = {};
 
diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
index c81c8c54..ed789f0 100644
--- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java
+++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -21,6 +21,7 @@
 import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
 import android.security.usermanager.IKeystoreUserManager;
+import android.system.keystore2.Domain;
 import android.system.keystore2.ResponseCode;
 import android.util.Log;
 
@@ -39,7 +40,7 @@
     }
 
     /**
-     * Informs keystore2 about adding a user
+     * Informs Keystore 2.0 about adding a user
      *
      * @param userId - Android user id of the user being added
      * @return 0 if successful or a {@code ResponseCode}
@@ -60,7 +61,7 @@
     }
 
     /**
-     * Informs keystore2 about removing a usergit mer
+     * Informs Keystore 2.0 about removing a usergit mer
      *
      * @param userId - Android user id of the user being removed
      * @return 0 if successful or a {@code ResponseCode}
@@ -81,7 +82,7 @@
     }
 
     /**
-     * Informs keystore2 about changing user's password
+     * Informs Keystore 2.0 about changing user's password
      *
      * @param userId   - Android user id of the user
      * @param password - a secret derived from the synthetic password provided by the
@@ -102,4 +103,22 @@
             return SYSTEM_ERROR;
         }
     }
+
+    /**
+     * Informs Keystore 2.0 that an app was uninstalled and the corresponding namspace is to
+     * be cleared.
+     */
+    public static int clearNamespace(@Domain int domain, long namespace) {
+        if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
+        try {
+            getService().clearNamespace(domain, namespace);
+            return 0;
+        } catch (ServiceSpecificException e) {
+            Log.e(TAG, "clearNamespace failed", e);
+            return e.errorCode;
+        } catch (Exception e) {
+            Log.e(TAG, "Can not connect to keystore", e);
+            return SYSTEM_ERROR;
+        }
+    }
 }
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index d00f5f6..684eebe 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -63,6 +63,7 @@
     AppUriAuthenticationPolicy getCredentialManagementAppPolicy();
     String getPredefinedAliasForPackageAndUri(String packageName, in Uri uri);
     void removeCredentialManagementApp();
+    boolean isCredentialManagementApp(String packageName);
 
     // APIs used by KeyChainActivity
     void setGrant(int uid, String alias, boolean value);
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index f0bcfe52..65a81cd 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -423,6 +423,15 @@
      * credentials. This is limited to unmanaged devices. The authentication policy must be
      * provided to be able to make this request successfully.
      *
+     * <p> This intent should be started using {@link Activity#startActivityForResult(Intent, int)}
+     * to verify whether the request was successful and whether the user accepted or denied the
+     * request. If the user successfully receives and accepts the request, the result code will be
+     * {@link Activity#RESULT_OK}, otherwise the result code will be
+     * {@link Activity#RESULT_CANCELED}.
+     *
+     * <p> {@link KeyChain#isCredentialManagementApp(Context)} should be used to determine whether
+     * an app is already the credential management app.
+     *
      * @param policy The authentication policy determines which alias for a private key and
      *               certificate pair should be used for authentication.
      */
@@ -591,6 +600,55 @@
     }
 
     /**
+     * Check whether the caller is the credential management app {@link CredentialManagementApp}.
+     * The credential management app has the ability to manage the user's KeyChain credentials
+     * on unmanaged devices.
+     *
+     * <p> {@link KeyChain#createManageCredentialsIntent} should be used by an app to request to
+     * become the credential management app. The user must approve this request before the app can
+     * manage the user's credentials. There can only be one credential management on the device.
+     *
+     * @return {@code true} if the caller is the credential management app.
+     */
+    public static boolean isCredentialManagementApp(@NonNull Context context) {
+        boolean isCredentialManagementApp = false;
+        try (KeyChainConnection keyChainConnection = KeyChain.bind(context)) {
+            isCredentialManagementApp = keyChainConnection.getService()
+                    .isCredentialManagementApp(context.getPackageName());
+        } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
+        } catch (InterruptedException e) {
+            throw new RuntimeException("Interrupted while checking whether the caller is the "
+                    + "credential management app.", e);
+        } catch (SecurityException e) {
+            isCredentialManagementApp = false;
+        }
+        return isCredentialManagementApp;
+    }
+
+    /**
+     * Called by the credential management app to get the authentication policy
+     * {@link AppUriAuthenticationPolicy}.
+     *
+     * @return the credential management app's authentication policy.
+     * @throws SecurityException if the caller is not the credential management app.
+     */
+    @NonNull
+    public static AppUriAuthenticationPolicy getCredentialManagementAppPolicy(
+            @NonNull Context context) throws SecurityException {
+        AppUriAuthenticationPolicy policy = null;
+        try (KeyChainConnection keyChainConnection = KeyChain.bind(context)) {
+            policy = keyChainConnection.getService().getCredentialManagementAppPolicy();
+        } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
+        } catch (InterruptedException e) {
+            throw new RuntimeException(
+                    "Interrupted while getting credential management app policy.", e);
+        }
+        return policy;
+    }
+
+    /**
      * Set a credential management app. The credential management app has the ability to manage
      * the user's KeyChain credentials on unmanaged devices.
      *
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 198df40..93658e6 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -43,6 +43,7 @@
 import android.security.keystore.KeyProperties;
 import android.security.keystore.KeystoreResponse;
 import android.security.keystore.UserNotAuthenticatedException;
+import android.system.keystore2.Domain;
 import android.util.Log;
 
 import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
@@ -466,6 +467,9 @@
 
     public boolean clearUid(int uid) {
         try {
+            if (android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) {
+                return AndroidKeyStoreMaintenance.clearNamespace(Domain.APP, uid) == 0;
+            }
             return mBinder.clear_uid(uid) == NO_ERROR;
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
diff --git a/keystore/java/android/security/KeyStore2.java b/keystore/java/android/security/KeyStore2.java
index 476e4d7..6ac3821 100644
--- a/keystore/java/android/security/KeyStore2.java
+++ b/keystore/java/android/security/KeyStore2.java
@@ -24,6 +24,7 @@
 import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
 import android.security.keymaster.KeymasterDefs;
+import android.system.keystore2.Domain;
 import android.system.keystore2.IKeystoreService;
 import android.system.keystore2.KeyDescriptor;
 import android.system.keystore2.KeyEntryResponse;
@@ -157,6 +158,50 @@
     }
 
     /**
+     * Grant string prefix as used by the keystore boringssl engine. Must be kept in sync
+     * with system/security/keystore-engine. Note: The prefix here includes the 0x which
+     * std::stringstream used in keystore-engine needs to identify the number as hex represented.
+     * Here we include it in the prefix, because Long#parseUnsignedLong does not understand it
+     * and gets the radix as explicit argument.
+     * @hide
+     */
+    private static final String KEYSTORE_ENGINE_GRANT_ALIAS_PREFIX =
+            "ks2_keystore-engine_grant_id:0x";
+
+    /**
+     * This function turns a grant identifier into a specific string that is understood by the
+     * keystore-engine in system/security/keystore-engine. Is only used by VPN and WI-FI components
+     * to allow certain system components like racoon or vendor components like WPA supplicant
+     * to use keystore keys with boring ssl.
+     *
+     * @param grantId the grant id as returned by {@link #grant} in the {@code nspace} filed of
+     *                the resulting {@code KeyDescriptor}.
+     * @return The grant descriptor string.
+     * @hide
+     */
+    public static String makeKeystoreEngineGrantString(long grantId) {
+        return String.format("%s%016X", KEYSTORE_ENGINE_GRANT_ALIAS_PREFIX, grantId);
+    }
+
+    /**
+     * Convenience function to turn a keystore engine grant string as returned by
+     * {@link #makeKeystoreEngineGrantString(long)} back into a grant KeyDescriptor.
+     *
+     * @param grantString As string returned by {@link #makeKeystoreEngineGrantString(long)}
+     * @return The grant key descriptor.
+     * @hide
+     */
+    public static KeyDescriptor keystoreEngineGrantString2KeyDescriptor(String grantString) {
+        KeyDescriptor key = new KeyDescriptor();
+        key.domain = Domain.GRANT;
+        key.nspace = Long.parseUnsignedLong(
+                grantString.substring(KEYSTORE_ENGINE_GRANT_ALIAS_PREFIX.length()), 16);
+        key.alias = null;
+        key.blob = null;
+        return key;
+    }
+
+    /**
      * Create a grant that allows the grantee identified by {@code granteeUid} to use
      * the key specified by {@code descriptor} withint the restrictions given by
      * {@code accessVectore}.
diff --git a/keystore/java/android/security/LegacyVpnProfileStore.java b/keystore/java/android/security/LegacyVpnProfileStore.java
new file mode 100644
index 0000000..41cfb27
--- /dev/null
+++ b/keystore/java/android/security/LegacyVpnProfileStore.java
@@ -0,0 +1,142 @@
+/*
+ * 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 android.security;
+
+import android.annotation.NonNull;
+import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
+import android.security.keystore.AndroidKeyStoreProvider;
+import android.security.vpnprofilestore.IVpnProfileStore;
+import android.util.Log;
+
+/**
+ * @hide This class allows legacy VPN access to its profiles that were stored in Keystore.
+ * The storage of unstructured blobs in Android Keystore is going away, because there is no
+ * architectural or security benefit of storing profiles in keystore over storing them
+ * in the file system. This class allows access to the blobs that still exist in keystore.
+ * And it stores new blob in a database that is still owned by Android Keystore.
+ */
+public class LegacyVpnProfileStore {
+    private static final String TAG = "LegacyVpnProfileStore";
+
+    public static final int SYSTEM_ERROR = IVpnProfileStore.ERROR_SYSTEM_ERROR;
+    public static final int PROFILE_NOT_FOUND = IVpnProfileStore.ERROR_PROFILE_NOT_FOUND;
+
+    private static final String VPN_PROFILE_STORE_SERVICE_NAME = "android.security.vpnprofilestore";
+
+    private static IVpnProfileStore getService() {
+        return IVpnProfileStore.Stub.asInterface(
+                    ServiceManager.checkService(VPN_PROFILE_STORE_SERVICE_NAME));
+    }
+
+    /**
+     * Stores the profile under the alias in the profile database. Existing profiles by the
+     * same name will be replaced.
+     * @param alias The name of the profile
+     * @param profile The profile.
+     * @return true if the profile was successfully added. False otherwise.
+     * @hide
+     */
+    public static boolean put(@NonNull String alias, @NonNull byte[] profile) {
+        try {
+            if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
+                getService().put(alias, profile);
+                return true;
+            } else {
+                return KeyStore.getInstance().put(
+                        alias, profile, KeyStore.UID_SELF, 0);
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to put vpn profile.", e);
+            return false;
+        }
+    }
+
+    /**
+     * Retrieves a profile by the name alias from the profile database.
+     * @param alias Name of the profile to retrieve.
+     * @return The unstructured blob, that is the profile that was stored using
+     *         LegacyVpnProfileStore#put or with
+     *         android.security.Keystore.put(Credentials.VPN + alias).
+     *         Returns null if no profile was found.
+     * @hide
+     */
+    public static byte[] get(@NonNull String alias) {
+        try {
+            if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
+                return getService().get(alias);
+            } else {
+                return KeyStore.getInstance().get(alias, true /* suppressKeyNotFoundWarning */);
+            }
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode != PROFILE_NOT_FOUND) {
+                Log.e(TAG, "Failed to get vpn profile.", e);
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to get vpn profile.", e);
+        }
+        return null;
+    }
+
+    /**
+     * Removes a profile by the name alias from the profile database.
+     * @param alias Name of the profile to be removed.
+     * @return True if a profile was removed. False if no such profile was found.
+     * @hide
+     */
+    public static boolean remove(@NonNull String alias) {
+        try {
+            if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
+                getService().remove(alias);
+                return true;
+            } else {
+                return KeyStore.getInstance().delete(alias);
+            }
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode != PROFILE_NOT_FOUND) {
+                Log.e(TAG, "Failed to remove vpn profile.", e);
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to remove vpn profile.", e);
+        }
+        return false;
+    }
+
+    /**
+     * Lists the vpn profiles stored in the database.
+     * @return An array of strings representing the aliases stored in the profile database.
+     *         The return value may be empty but never null.
+     * @hide
+     */
+    public static @NonNull String[] list(@NonNull String prefix) {
+        try {
+            if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
+                final String[] aliases = getService().list(prefix);
+                for (int i = 0; i < aliases.length; ++i) {
+                    aliases[i] = aliases[i].substring(prefix.length());
+                }
+                return aliases;
+            } else {
+                final String[] result = KeyStore.getInstance().list(prefix);
+                return result != null ? result : new String[0];
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to list vpn profiles.", e);
+        }
+        return new String[0];
+    }
+}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index 35059ac..d36695b 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -43,6 +43,7 @@
 
 import javax.crypto.Cipher;
 import javax.crypto.Mac;
+import javax.crypto.SecretKey;
 
 /**
  * A provider focused on providing JCA interfaces for the Android KeyStore.
@@ -299,13 +300,26 @@
         }
     }
 
+    /** @hide **/
+    @NonNull
+    public static SecretKey loadAndroidKeyStoreSecretKeyFromKeystore(
+            @NonNull KeyStore2 keyStore, @NonNull KeyDescriptor descriptor)
+            throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
+
+        AndroidKeyStoreKey key =
+                loadAndroidKeyStoreKeyFromKeystore(keyStore, descriptor);
+        if (key instanceof SecretKey) {
+            return (SecretKey) key;
+        } else {
+            throw new UnrecoverableKeyException("No secret key found by the given alias.");
+        }
+    }
 
     @NonNull
     private static AndroidKeyStoreSecretKey makeAndroidKeyStoreSecretKeyFromKeyEntryResponse(
             @NonNull KeyDescriptor descriptor,
             @NonNull KeyEntryResponse response, int algorithm, int digest)
             throws UnrecoverableKeyException {
-
         @KeyProperties.KeyAlgorithmEnum String keyAlgorithmString;
         try {
             keyAlgorithmString = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm(
@@ -337,7 +351,6 @@
     public static AndroidKeyStoreKey loadAndroidKeyStoreKeyFromKeystore(
             @NonNull KeyStore2 keyStore, @NonNull String alias, int namespace)
             throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
-
         KeyDescriptor descriptor = new KeyDescriptor();
         if (namespace == KeyProperties.NAMESPACE_APPLICATION) {
             descriptor.nspace = KeyProperties.NAMESPACE_APPLICATION; // ignored;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
index 7376d98..85bd24c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
@@ -24,7 +24,9 @@
 import com.android.wm.shell.common.annotations.ExternalThread;
 import com.android.wm.shell.draganddrop.DragAndDropController;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
+import com.android.wm.shell.pip.phone.PipTouchHandler;
 import com.android.wm.shell.splitscreen.SplitScreenController;
+import com.android.wm.shell.startingsurface.StartingSurface;
 import com.android.wm.shell.transition.Transitions;
 
 import java.util.Optional;
@@ -41,9 +43,11 @@
     private final Optional<LegacySplitScreenController> mLegacySplitScreenOptional;
     private final Optional<SplitScreenController> mSplitScreenOptional;
     private final Optional<AppPairsController> mAppPairsOptional;
+    private final Optional<PipTouchHandler> mPipTouchHandlerOptional;
     private final FullscreenTaskListener mFullscreenTaskListener;
     private final ShellExecutor mMainExecutor;
     private final Transitions mTransitions;
+    private final Optional<StartingSurface> mStartingSurfaceOptional;
 
     private final InitImpl mImpl = new InitImpl();
 
@@ -53,6 +57,8 @@
             Optional<LegacySplitScreenController> legacySplitScreenOptional,
             Optional<SplitScreenController> splitScreenOptional,
             Optional<AppPairsController> appPairsOptional,
+            Optional<StartingSurface> startingSurfaceOptional,
+            Optional<PipTouchHandler> pipTouchHandlerOptional,
             FullscreenTaskListener fullscreenTaskListener,
             Transitions transitions,
             ShellExecutor mainExecutor) {
@@ -62,6 +68,8 @@
                 legacySplitScreenOptional,
                 splitScreenOptional,
                 appPairsOptional,
+                startingSurfaceOptional,
+                pipTouchHandlerOptional,
                 fullscreenTaskListener,
                 transitions,
                 mainExecutor).mImpl;
@@ -73,6 +81,8 @@
             Optional<LegacySplitScreenController> legacySplitScreenOptional,
             Optional<SplitScreenController> splitScreenOptional,
             Optional<AppPairsController> appPairsOptional,
+            Optional<StartingSurface> startingSurfaceOptional,
+            Optional<PipTouchHandler> pipTouchHandlerOptional,
             FullscreenTaskListener fullscreenTaskListener,
             Transitions transitions,
             ShellExecutor mainExecutor) {
@@ -83,8 +93,10 @@
         mSplitScreenOptional = splitScreenOptional;
         mAppPairsOptional = appPairsOptional;
         mFullscreenTaskListener = fullscreenTaskListener;
+        mPipTouchHandlerOptional = pipTouchHandlerOptional;
         mTransitions = transitions;
         mMainExecutor = mainExecutor;
+        mStartingSurfaceOptional = startingSurfaceOptional;
     }
 
     private void init() {
@@ -93,6 +105,7 @@
 
         mShellTaskOrganizer.addListenerForType(
                 mFullscreenTaskListener, TASK_LISTENER_TYPE_FULLSCREEN);
+        mStartingSurfaceOptional.ifPresent(mShellTaskOrganizer::initStartingSurface);
         // Register the shell organizer
         mShellTaskOrganizer.registerOrganizer();
 
@@ -105,6 +118,11 @@
         if (Transitions.ENABLE_SHELL_TRANSITIONS) {
             mTransitions.register(mShellTaskOrganizer);
         }
+
+        // TODO(b/181599115): This should really be the pip controller, but until we can provide the
+        // controller instead of the feature interface, can just initialize the touch handler if
+        // needed
+        mPipTouchHandlerOptional.ifPresent((handler) -> handler.init());
     }
 
     @ExternalThread
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index efc55c4..9ddeb2f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -44,7 +44,7 @@
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.sizecompatui.SizeCompatUIController;
-import com.android.wm.shell.startingsurface.StartingSurfaceDrawer;
+import com.android.wm.shell.startingsurface.StartingSurface;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -110,7 +110,7 @@
     private final ArrayMap<IBinder, TaskListener> mLaunchCookieToListener = new ArrayMap<>();
 
     private final Object mLock = new Object();
-    private final StartingSurfaceDrawer mStartingSurfaceDrawer;
+    private StartingSurface mStartingSurface;
 
     /**
      * In charge of showing size compat UI. Can be {@code null} if device doesn't support size
@@ -120,23 +120,19 @@
     private final SizeCompatUIController mSizeCompatUI;
 
     public ShellTaskOrganizer(ShellExecutor mainExecutor, Context context) {
-        this(null /* taskOrganizerController */, mainExecutor, context, null /* sizeCompatUI */,
-                new StartingSurfaceDrawer(context, mainExecutor));
+        this(null /* taskOrganizerController */, mainExecutor, context, null /* sizeCompatUI */);
     }
 
     public ShellTaskOrganizer(ShellExecutor mainExecutor, Context context, @Nullable
             SizeCompatUIController sizeCompatUI) {
-        this(null /* taskOrganizerController */, mainExecutor, context, sizeCompatUI,
-                new StartingSurfaceDrawer(context, mainExecutor));
+        this(null /* taskOrganizerController */, mainExecutor, context, sizeCompatUI);
     }
 
     @VisibleForTesting
     ShellTaskOrganizer(ITaskOrganizerController taskOrganizerController, ShellExecutor mainExecutor,
-            Context context, @Nullable SizeCompatUIController sizeCompatUI,
-            StartingSurfaceDrawer startingSurfaceDrawer) {
+            Context context, @Nullable SizeCompatUIController sizeCompatUI) {
         super(taskOrganizerController, mainExecutor);
         mSizeCompatUI = sizeCompatUI;
-        mStartingSurfaceDrawer = startingSurfaceDrawer;
     }
 
     @Override
@@ -163,6 +159,15 @@
     }
 
     /**
+     * @hide
+     */
+    public void initStartingSurface(StartingSurface startingSurface) {
+        synchronized (mLock) {
+            mStartingSurface = startingSurface;
+        }
+    }
+
+    /**
      * Adds a listener for a specific task id.
      */
     public void addListenerForTaskId(TaskListener listener, int taskId) {
@@ -254,17 +259,23 @@
 
     @Override
     public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
-        mStartingSurfaceDrawer.addStartingWindow(info, appToken);
+        if (mStartingSurface != null) {
+            mStartingSurface.addStartingWindow(info, appToken);
+        }
     }
 
     @Override
     public void removeStartingWindow(int taskId) {
-        mStartingSurfaceDrawer.removeStartingWindow(taskId);
+        if (mStartingSurface != null) {
+            mStartingSurface.removeStartingWindow(taskId);
+        }
     }
 
     @Override
     public void copySplashScreenView(int taskId) {
-        mStartingSurfaceDrawer.copySplashScreenView(taskId);
+        if (mStartingSurface != null) {
+            mStartingSurface.copySplashScreenView(taskId);
+        }
     }
 
     @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
index 5992447..46884fe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
@@ -157,6 +157,7 @@
         });
         options.setLaunchCookie(launchCookie);
         options.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        options.setRemoveWithTaskOrganizer(true);
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/WindowManagerShellWrapper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/WindowManagerShellWrapper.java
index 59271e9..e6e6d4a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/WindowManagerShellWrapper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/WindowManagerShellWrapper.java
@@ -22,7 +22,7 @@
 
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.pip.PinnedStackListenerForwarder;
-import com.android.wm.shell.pip.PinnedStackListenerForwarder.PinnedStackListener;
+import com.android.wm.shell.pip.PinnedStackListenerForwarder.PinnedTaskListener;
 
 /**
  * The singleton wrapper to communicate between WindowManagerService and WMShell features
@@ -46,7 +46,7 @@
      * Adds a pinned stack listener, which will receive updates from the window manager service
      * along with any other pinned stack listeners that were added via this method.
      */
-    public void addPinnedStackListener(PinnedStackListener listener)
+    public void addPinnedStackListener(PinnedTaskListener listener)
             throws RemoteException {
         mPinnedStackListenerForwarder.addListener(listener);
         mPinnedStackListenerForwarder.register(DEFAULT_DISPLAY);
@@ -55,7 +55,7 @@
     /**
      * Removes a pinned stack listener.
      */
-    public void removePinnedStackListener(PinnedStackListener listener) {
+    public void removePinnedStackListener(PinnedTaskListener listener) {
         mPinnedStackListenerForwarder.removeListener(listener);
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
index 79f9dcd..562b32b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
@@ -34,6 +34,7 @@
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayImeController;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.split.SplitLayout;
 
@@ -57,12 +58,14 @@
     private final AppPairsController mController;
     private final SyncTransactionQueue mSyncQueue;
     private final DisplayController mDisplayController;
+    private final DisplayImeController mDisplayImeController;
     private SplitLayout mSplitLayout;
 
     AppPair(AppPairsController controller) {
         mController = controller;
         mSyncQueue = controller.getSyncTransactionQueue();
         mDisplayController = controller.getDisplayController();
+        mDisplayImeController = controller.getDisplayImeController();
     }
 
     int getRootTaskId() {
@@ -97,7 +100,7 @@
         mSplitLayout = new SplitLayout(TAG + "SplitDivider",
                 mDisplayController.getDisplayContext(mRootTaskInfo.displayId),
                 mRootTaskInfo.configuration, this /* layoutChangeListener */,
-                b -> b.setParent(mRootTaskLeash));
+                b -> b.setParent(mRootTaskLeash), mDisplayImeController);
 
         final WindowContainerToken token1 = task1.token;
         final WindowContainerToken token2 = task2.token;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java
index 0415f12..b159333 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java
@@ -23,17 +23,16 @@
 import android.util.SparseArray;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayImeController;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 
 import java.io.PrintWriter;
-import java.util.concurrent.TimeUnit;
 
 /**
  * Class manages app-pairs multitasking mode and implements the main interface {@link AppPairs}.
@@ -50,12 +49,15 @@
     // Active app-pairs mapped by root task id key.
     private final SparseArray<AppPair> mActiveAppPairs = new SparseArray<>();
     private final DisplayController mDisplayController;
+    private final DisplayImeController mDisplayImeController;
 
     public AppPairsController(ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue,
-                DisplayController displayController, ShellExecutor mainExecutor) {
+            DisplayController displayController, ShellExecutor mainExecutor,
+            DisplayImeController displayImeController) {
         mTaskOrganizer = organizer;
         mSyncQueue = syncQueue;
         mDisplayController = displayController;
+        mDisplayImeController = displayImeController;
         mMainExecutor = mainExecutor;
     }
 
@@ -130,18 +132,22 @@
         }
     }
 
-    public ShellTaskOrganizer getTaskOrganizer() {
+    ShellTaskOrganizer getTaskOrganizer() {
         return mTaskOrganizer;
     }
 
-    public SyncTransactionQueue getSyncTransactionQueue() {
+    SyncTransactionQueue getSyncTransactionQueue() {
         return mSyncQueue;
     }
 
-    public DisplayController getDisplayController() {
+    DisplayController getDisplayController() {
         return mDisplayController;
     }
 
+    DisplayImeController getDisplayImeController() {
+        return mDisplayImeController;
+    }
+
     public void dump(@NonNull PrintWriter pw, String prefix) {
         final String innerPrefix = prefix + "  ";
         final String childPrefix = innerPrefix + "  ";
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 047df5b..1320780 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -1213,7 +1213,7 @@
 
     /** PinnedStackListener that dispatches IME visibility updates to the stack. */
     //TODO(b/170442945): Better way to do this / insets listener?
-    private class BubblesImeListener extends PinnedStackListenerForwarder.PinnedStackListener {
+    private class BubblesImeListener extends PinnedStackListenerForwarder.PinnedTaskListener {
         @Override
         public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
             if (mStackView != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
index 19c3cf9..57a2b6c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
@@ -227,24 +227,30 @@
     /*
      * Fade animation for consecutive flyouts.
      */
-    void animateUpdate(Bubble.FlyoutMessage flyoutMessage, float parentWidth, float stackY) {
+    void animateUpdate(Bubble.FlyoutMessage flyoutMessage, float parentWidth, PointF stackPos,
+            boolean hideDot) {
         final Runnable afterFadeOut = () -> {
             updateFlyoutMessage(flyoutMessage, parentWidth);
             // Wait for TextViews to layout with updated height.
             post(() -> {
-                mFlyoutY = stackY + (mBubbleSize - mFlyoutTextContainer.getHeight()) / 2f;
-                fade(true /* in */, () -> {} /* after */);
+                fade(true /* in */, stackPos, hideDot, () -> {} /* after */);
             } /* after */ );
         };
-        fade(false /* in */, afterFadeOut);
+        fade(false /* in */, stackPos, hideDot, afterFadeOut);
     }
 
     /*
      * Fade-out above or fade-in from below.
      */
-    private void fade(boolean in, Runnable afterFade) {
+    private void fade(boolean in, PointF stackPos, boolean hideDot, Runnable afterFade) {
+        mFlyoutY = stackPos.y + (mBubbleSize - mFlyoutTextContainer.getHeight()) / 2f;
+
         setAlpha(in ? 0f : 1f);
         setTranslationY(in ? mFlyoutY + FLYOUT_FADE_Y : mFlyoutY);
+        updateFlyoutX(stackPos.x);
+        setTranslationX(mRestingTranslationX);
+        updateDot(stackPos, hideDot);
+
         animate()
                 .alpha(in ? 1f : 0f)
                 .setDuration(in ? FLYOUT_FADE_IN_DURATION : FLYOUT_FADE_OUT_DURATION)
@@ -287,6 +293,33 @@
         mMessageText.setText(flyoutMessage.message);
     }
 
+    void updateFlyoutX(float stackX) {
+        // Calculate the translation required to position the flyout next to the bubble stack,
+        // with the desired padding.
+        mRestingTranslationX = mArrowPointingLeft
+                ? stackX + mBubbleSize + mFlyoutSpaceFromBubble
+                : stackX - getWidth() - mFlyoutSpaceFromBubble;
+    }
+
+    void updateDot(PointF stackPos, boolean hideDot) {
+        // Calculate the difference in size between the flyout and the 'dot' so that we can
+        // transform into the dot later.
+        final float newDotSize = hideDot ? 0f : mNewDotSize;
+        mFlyoutToDotWidthDelta = getWidth() - newDotSize;
+        mFlyoutToDotHeightDelta = getHeight() - newDotSize;
+
+        // Calculate the translation values needed to be in the correct 'new dot' position.
+        final float adjustmentForScaleAway = hideDot ? 0f : (mOriginalDotSize / 2f);
+        final float dotPositionX = stackPos.x + mDotCenter[0] - adjustmentForScaleAway;
+        final float dotPositionY = stackPos.y + mDotCenter[1] - adjustmentForScaleAway;
+
+        final float distanceFromFlyoutLeftToDotCenterX = mRestingTranslationX - dotPositionX;
+        final float distanceFromLayoutTopToDotCenterY = mFlyoutY - dotPositionY;
+
+        mTranslationXWhenDot = -distanceFromFlyoutLeftToDotCenterX;
+        mTranslationYWhenDot = -distanceFromLayoutTopToDotCenterY;
+    }
+
     /** Configures the flyout, collapsed into dot form. */
     void setupFlyoutStartingAsDot(
             Bubble.FlyoutMessage flyoutMessage,
@@ -322,29 +355,8 @@
             mFlyoutY =
                     stackPos.y + (mBubbleSize - mFlyoutTextContainer.getHeight()) / 2f;
             setTranslationY(mFlyoutY);
-
-            // Calculate the translation required to position the flyout next to the bubble stack,
-            // with the desired padding.
-            mRestingTranslationX = mArrowPointingLeft
-                    ? stackPos.x + mBubbleSize + mFlyoutSpaceFromBubble
-                    : stackPos.x - getWidth() - mFlyoutSpaceFromBubble;
-
-            // Calculate the difference in size between the flyout and the 'dot' so that we can
-            // transform into the dot later.
-            final float newDotSize = hideDot ? 0f : mNewDotSize;
-            mFlyoutToDotWidthDelta = getWidth() - newDotSize;
-            mFlyoutToDotHeightDelta = getHeight() - newDotSize;
-
-            // Calculate the translation values needed to be in the correct 'new dot' position.
-            final float adjustmentForScaleAway = hideDot ? 0f : (mOriginalDotSize / 2f);
-            final float dotPositionX = stackPos.x + mDotCenter[0] - adjustmentForScaleAway;
-            final float dotPositionY = stackPos.y + mDotCenter[1] - adjustmentForScaleAway;
-
-            final float distanceFromFlyoutLeftToDotCenterX = mRestingTranslationX - dotPositionX;
-            final float distanceFromLayoutTopToDotCenterY = mFlyoutY - dotPositionY;
-
-            mTranslationXWhenDot = -distanceFromFlyoutLeftToDotCenterX;
-            mTranslationYWhenDot = -distanceFromLayoutTopToDotCenterY;
+            updateFlyoutX(stackPos.x);
+            updateDot(stackPos, hideDot);
             if (onLayoutComplete != null) {
                 onLayoutComplete.run();
             }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index a3edc20..78820a8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -1539,19 +1539,16 @@
      * Update bubble order and pointer position.
      */
     public void updateBubbleOrder(List<Bubble> bubbles) {
-        if (isExpansionAnimating()) {
-            return;
-        }
         final Runnable reorder = () -> {
             for (int i = 0; i < bubbles.size(); i++) {
                 Bubble bubble = bubbles.get(i);
                 mBubbleContainer.reorderView(bubble.getIconView(), i);
             }
         };
-        if (mIsExpanded) {
+        if (mIsExpanded || isExpansionAnimating()) {
             reorder.run();
             updateBadgesAndZOrder(false /* setBadgeForCollapsedStack */);
-        } else {
+        } else if (!isExpansionAnimating()) {
             List<View> bubbleViews = bubbles.stream()
                     .map(b -> b.getIconView()).collect(Collectors.toList());
             mStackAnimationController.animateReorder(bubbleViews, reorder);
@@ -2434,7 +2431,7 @@
 
             if (mFlyout.getVisibility() == View.VISIBLE) {
                 mFlyout.animateUpdate(bubble.getFlyoutMessage(), getWidth(),
-                        mStackAnimationController.getStackPosition().y);
+                        mStackAnimationController.getStackPosition(), !bubble.showDot());
             } else {
                 mFlyout.setVisibility(INVISIBLE);
                 mFlyout.setupFlyoutStartingAsDot(bubble.getFlyoutMessage(),
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
index 58a4baf..f118b1e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
@@ -22,6 +22,8 @@
 import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
 import static android.os.Process.SYSTEM_UID;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
+import static android.util.RotationUtils.rotateBounds;
+import static android.util.RotationUtils.rotateInsets;
 import static android.view.Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
 import static android.view.Surface.ROTATION_0;
 import static android.view.Surface.ROTATION_270;
@@ -37,7 +39,6 @@
 import android.os.SystemProperties;
 import android.provider.Settings;
 import android.util.DisplayMetrics;
-import android.util.RotationUtils;
 import android.util.Size;
 import android.view.Display;
 import android.view.DisplayCutout;
@@ -49,6 +50,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
 
 /**
  * Contains information about the layout-properties of a display. This refers to internal layout
@@ -81,6 +83,31 @@
     private boolean mHasStatusBar = false;
     private int mNavBarFrameHeight = 0;
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof DisplayLayout)) return false;
+        final DisplayLayout other = (DisplayLayout) o;
+        return mUiMode == other.mUiMode
+                && mWidth == other.mWidth
+                && mHeight == other.mHeight
+                && Objects.equals(mCutout, other.mCutout)
+                && mRotation == other.mRotation
+                && mDensityDpi == other.mDensityDpi
+                && Objects.equals(mNonDecorInsets, other.mNonDecorInsets)
+                && Objects.equals(mStableInsets, other.mStableInsets)
+                && mHasNavigationBar == other.mHasNavigationBar
+                && mHasStatusBar == other.mHasStatusBar
+                && mNavBarFrameHeight == other.mNavBarFrameHeight;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mUiMode, mWidth, mHeight, mCutout, mRotation, mDensityDpi,
+                mNonDecorInsets, mStableInsets, mHasNavigationBar, mHasStatusBar,
+                mNavBarFrameHeight);
+    }
+
     /**
      * Create empty layout.
      */
@@ -241,38 +268,6 @@
     }
 
     /**
-     * Rotates bounds as if parentBounds and bounds are a group. The group is rotated by `delta`
-     * 90-degree counter-clockwise increments. This assumes that parentBounds is at 0,0 and
-     * remains at 0,0 after rotation.
-     *
-     * Only 'bounds' is mutated.
-     */
-    public static void rotateBounds(Rect inOutBounds, Rect parentBounds, int delta) {
-        int rdelta = ((delta % 4) + 4) % 4;
-        int origLeft = inOutBounds.left;
-        switch (rdelta) {
-            case 0:
-                return;
-            case 1:
-                inOutBounds.left = inOutBounds.top;
-                inOutBounds.top = parentBounds.right - inOutBounds.right;
-                inOutBounds.right = inOutBounds.bottom;
-                inOutBounds.bottom = parentBounds.right - origLeft;
-                return;
-            case 2:
-                inOutBounds.left = parentBounds.right - inOutBounds.right;
-                inOutBounds.right = parentBounds.right - origLeft;
-                return;
-            case 3:
-                inOutBounds.left = parentBounds.bottom - inOutBounds.bottom;
-                inOutBounds.bottom = inOutBounds.right;
-                inOutBounds.right = parentBounds.bottom - inOutBounds.top;
-                inOutBounds.top = origLeft;
-                return;
-        }
-    }
-
-    /**
      * Calculates the stable insets if we already have the non-decor insets.
      */
     private static void convertNonDecorInsetsToStableInsets(Resources res, Rect inOutInsets,
@@ -359,8 +354,7 @@
         if (rotation == ROTATION_0) {
             return computeSafeInsets(cutout, displayWidth, displayHeight);
         }
-        final Insets waterfallInsets =
-                RotationUtils.rotateInsets(cutout.getWaterfallInsets(), rotation);
+        final Insets waterfallInsets = rotateInsets(cutout.getWaterfallInsets(), rotation);
         final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
         Rect[] cutoutRects = cutout.getBoundingRectsAll();
         final Rect[] newBounds = new Rect[cutoutRects.length];
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index fb70cbe5..4bb8e9b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -39,12 +39,12 @@
 import android.view.IWindowSessionCallback;
 import android.view.InsetsSourceControl;
 import android.view.InsetsState;
+import android.view.ScrollCaptureResponse;
 import android.view.SurfaceControl;
-import android.view.SurfaceSession;
 import android.view.SurfaceControlViewHost;
+import android.view.SurfaceSession;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewRootImpl;
 import android.view.WindowManager;
 import android.view.WindowlessWindowManager;
 import android.window.ClientWindowFrames;
@@ -371,7 +371,11 @@
         @Override
         public void requestScrollCapture(IScrollCaptureCallbacks callbacks) {
             try {
-                callbacks.onUnavailable();
+                callbacks.onScrollCaptureResponse(
+                        new ScrollCaptureResponse.Builder()
+                                .setDescription("Not Implemented")
+                                .build());
+
             } catch (RemoteException ex) {
                 // ignore
             }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java
index e94080a..3b67005 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java
@@ -227,7 +227,7 @@
     }
 
     @Override
-    public void onActivityDismissingDockedStack() {
+    public void onActivityDismissingDockedTask() {
         mMainHandler.sendEmptyMessage(ON_ACTIVITY_DISMISSING_DOCKED_STACK);
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index c27c929..b9fdaa1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -36,11 +36,13 @@
 import com.android.internal.policy.DividerSnapAlgorithm;
 import com.android.wm.shell.R;
 import com.android.wm.shell.animation.Interpolators;
+import com.android.wm.shell.common.DisplayImeController;
 
 /**
- * Stack divider for app pair.
+ * Divider for multi window splits.
  */
-public class DividerView extends FrameLayout implements View.OnTouchListener {
+public class DividerView extends FrameLayout implements View.OnTouchListener,
+        DisplayImeController.ImePositionProcessor {
     public static final long TOUCH_ANIMATION_DURATION = 150;
     public static final long TOUCH_RELEASE_ANIMATION_DURATION = 200;
 
@@ -56,6 +58,7 @@
     private boolean mMoving;
     private int mStartPos;
     private GestureDetector mDoubleTapDetector;
+    private boolean mInteractive;
 
     public DividerView(@NonNull Context context) {
         super(context);
@@ -91,12 +94,19 @@
         mTouchElevation = getResources().getDimensionPixelSize(
                 R.dimen.docked_stack_divider_lift_elevation);
         mDoubleTapDetector = new GestureDetector(getContext(), new DoubleTapListener());
+        mInteractive = true;
         setOnTouchListener(this);
     }
 
     @Override
+    public void onImeVisibilityChanged(int displayId, boolean isShowing) {
+        if (displayId != getDisplay().getDisplayId()) return;
+        setInteractive(!isShowing);
+    }
+
+    @Override
     public boolean onTouch(View v, MotionEvent event) {
-        if (mSplitLayout == null) {
+        if (mSplitLayout == null || !mInteractive) {
             return false;
         }
 
@@ -202,6 +212,13 @@
         mViewHost.relayout(lp);
     }
 
+    private void setInteractive(boolean interactive) {
+        if (interactive == mInteractive) return;
+        mInteractive = interactive;
+        releaseTouching();
+        mHandle.setVisibility(mInteractive ? View.VISIBLE : View.INVISIBLE);
+    }
+
     private boolean isLandscape() {
         return getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE;
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 60231df..bacff78 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -35,6 +35,7 @@
 
 import com.android.internal.policy.DividerSnapAlgorithm;
 import com.android.wm.shell.animation.Interpolators;
+import com.android.wm.shell.common.DisplayImeController;
 
 /**
  * Records and handles layout of splits. Helps to calculate proper bounds when configuration or
@@ -59,11 +60,13 @@
 
     public SplitLayout(String windowName, Context context, Configuration configuration,
             LayoutChangeListener layoutChangeListener,
-            SplitWindowManager.ParentContainerCallbacks parentContainerCallbacks) {
+            SplitWindowManager.ParentContainerCallbacks parentContainerCallbacks,
+            DisplayImeController displayImeController) {
         mContext = context.createConfigurationContext(configuration);
         mLayoutChangeListener = layoutChangeListener;
         mSplitWindowManager = new SplitWindowManager(
-                windowName, mContext, configuration, parentContainerCallbacks);
+                windowName, mContext, configuration, parentContainerCallbacks,
+                displayImeController);
 
         mDividerWindowWidth = context.getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.docked_stack_divider_thickness);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
index 87f0c25..f6efb01 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
@@ -46,6 +46,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.wm.shell.R;
+import com.android.wm.shell.common.DisplayImeController;
 
 /**
  * Holds view hierarchy of a root surface and helps to inflate {@link DividerView} for a split.
@@ -53,23 +54,27 @@
 public final class SplitWindowManager extends WindowlessWindowManager {
     private static final String TAG = SplitWindowManager.class.getSimpleName();
 
+    private final String mWindowName;
+    private final DisplayImeController mDisplayImeController;
     private final ParentContainerCallbacks mParentContainerCallbacks;
     private Context mContext;
     private SurfaceControlViewHost mViewHost;
     private SurfaceControl mLeash;
     private boolean mResizingSplits;
-    private final String mWindowName;
+    private DividerView mDividerView;
 
     public interface ParentContainerCallbacks {
         void attachToParentSurface(SurfaceControl.Builder b);
     }
 
     public SplitWindowManager(String windowName, Context context, Configuration config,
-            ParentContainerCallbacks parentContainerCallbacks) {
+            ParentContainerCallbacks parentContainerCallbacks,
+            DisplayImeController displayImeController) {
         super(config, null /* rootSurface */, null /* hostInputToken */);
         mContext = context.createConfigurationContext(config);
         mParentContainerCallbacks = parentContainerCallbacks;
         mWindowName = windowName;
+        mDisplayImeController = displayImeController;
     }
 
     @Override
@@ -103,14 +108,16 @@
 
     /** Inflates {@link DividerView} on to the root surface. */
     void init(SplitLayout splitLayout) {
-        if (mViewHost == null) {
-            mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
+        if (mDividerView != null || mViewHost != null) {
+            throw new UnsupportedOperationException(
+                    "Try to inflate divider view again without release first");
         }
 
-        final Rect dividerBounds = splitLayout.getDividerBounds();
-        final DividerView dividerView = (DividerView) LayoutInflater.from(mContext)
+        mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
+        mDividerView = (DividerView) LayoutInflater.from(mContext)
                 .inflate(R.layout.split_divider, null /* root */);
 
+        final Rect dividerBounds = splitLayout.getDividerBounds();
         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                 dividerBounds.width(), dividerBounds.height(), TYPE_DOCK_DIVIDER,
                 FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL | FLAG_WATCH_OUTSIDE_TOUCH
@@ -119,8 +126,9 @@
         lp.token = new Binder();
         lp.setTitle(mWindowName);
         lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
-        mViewHost.setView(dividerView, lp);
-        dividerView.setup(splitLayout, mViewHost);
+        mViewHost.setView(mDividerView, lp);
+        mDividerView.setup(splitLayout, mViewHost);
+        mDisplayImeController.addPositionProcessor(mDividerView);
     }
 
     /**
@@ -128,6 +136,11 @@
      * hierarchy.
      */
     void release() {
+        if (mDividerView != null) {
+            mDisplayImeController.removePositionProcessor(mDividerView);
+            mDividerView = null;
+        }
+
         if (mViewHost != null){
             mViewHost.release();
             mViewHost = null;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java
index 477ec33..40244fb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java
@@ -18,6 +18,7 @@
 
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.util.RotationUtils.rotateBounds;
 import static android.view.WindowManager.DOCKED_BOTTOM;
 import static android.view.WindowManager.DOCKED_INVALID;
 import static android.view.WindowManager.DOCKED_LEFT;
@@ -244,7 +245,7 @@
             DividerSnapAlgorithm snap = initSnapAlgorithmForRotation(context, tmpDL, dividerSize);
 
             tmpRect.set(bounds);
-            DisplayLayout.rotateBounds(tmpRect, displayRect, rotation - dl.rotation());
+            rotateBounds(tmpRect, displayRect, dl.rotation(), rotation);
             rotatedDisplayRect.set(0, 0, tmpDL.width(), tmpDL.height());
             final int dockSide = getPrimarySplitSide(tmpRect, rotatedDisplayRect,
                     tmpDL.getOrientation());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
index c8f8987..82468ad 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
@@ -105,7 +105,7 @@
             synchronized (mDockedRect) {
                 mTouchableRegion.set(region);
             }
-            WindowManagerGlobal.getWindowManagerService().setDockedStackDividerTouchRegion(
+            WindowManagerGlobal.getWindowManagerService().setDockedTaskDividerTouchRegion(
                     mTouchableRegion);
         } catch (RemoteException e) {
             Log.w(TAG, "Failed to set touchable region: " + e);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
index afc8a09..4c5cc22 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
@@ -202,6 +202,7 @@
                     animateWindows(token, leash, fromBounds, toBounds, direction,
                             mEnterExitAnimationDurationMs);
                     wct.setBounds(token, toBounds);
+                    wct.setAppBounds(token, toBounds);
                 });
         applyTransaction(wct);
     }
@@ -231,6 +232,7 @@
                     // DisplayRotationController will applyTransaction() after finish rotating
                     if (wct != null) {
                         wct.setBounds(token, null/* reset */);
+                        wct.setAppBounds(token, null/* reset */);
                     }
                 });
         tx.apply();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java
index 8f8ec47..b3b1ba7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java
@@ -20,7 +20,7 @@
 import android.content.ComponentName;
 import android.content.pm.ParceledListSlice;
 import android.os.RemoteException;
-import android.view.IPinnedStackListener;
+import android.view.IPinnedTaskListener;
 import android.view.WindowManagerGlobal;
 
 import androidx.annotation.BinderThread;
@@ -32,66 +32,66 @@
 /**
  * PinnedStackListener that simply forwards all calls to each listener added via
  * {@link #addListener}. This is necessary since calling
- * {@link com.android.server.wm.WindowManagerService#registerPinnedStackListener} replaces any
+ * {@link com.android.server.wm.WindowManagerService#registerPinnedTaskListener} replaces any
  * previously set listener.
  */
 public class PinnedStackListenerForwarder {
 
-    private final IPinnedStackListener mListenerImpl = new PinnedStackListenerImpl();
+    private final IPinnedTaskListener mListenerImpl = new PinnedTaskListenerImpl();
     private final ShellExecutor mMainExecutor;
-    private final ArrayList<PinnedStackListener> mListeners = new ArrayList<>();
+    private final ArrayList<PinnedTaskListener> mListeners = new ArrayList<>();
 
     public PinnedStackListenerForwarder(ShellExecutor mainExecutor) {
         mMainExecutor = mainExecutor;
     }
 
     /** Adds a listener to receive updates from the WindowManagerService. */
-    public void addListener(PinnedStackListener listener) {
+    public void addListener(PinnedTaskListener listener) {
         mListeners.add(listener);
     }
 
     /** Removes a listener so it will no longer receive updates from the WindowManagerService. */
-    public void removeListener(PinnedStackListener listener) {
+    public void removeListener(PinnedTaskListener listener) {
         mListeners.remove(listener);
     }
 
     public void register(int displayId) throws RemoteException {
-        WindowManagerGlobal.getWindowManagerService().registerPinnedStackListener(
+        WindowManagerGlobal.getWindowManagerService().registerPinnedTaskListener(
                 displayId, mListenerImpl);
     }
 
     private void onMovementBoundsChanged(boolean fromImeAdjustment) {
-        for (PinnedStackListener listener : mListeners) {
+        for (PinnedTaskListener listener : mListeners) {
             listener.onMovementBoundsChanged(fromImeAdjustment);
         }
     }
 
     private void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
-        for (PinnedStackListener listener : mListeners) {
+        for (PinnedTaskListener listener : mListeners) {
             listener.onImeVisibilityChanged(imeVisible, imeHeight);
         }
     }
 
     private void onActionsChanged(ParceledListSlice<RemoteAction> actions) {
-        for (PinnedStackListener listener : mListeners) {
+        for (PinnedTaskListener listener : mListeners) {
             listener.onActionsChanged(actions);
         }
     }
 
     private void onActivityHidden(ComponentName componentName) {
-        for (PinnedStackListener listener : mListeners) {
+        for (PinnedTaskListener listener : mListeners) {
             listener.onActivityHidden(componentName);
         }
     }
 
     private void onAspectRatioChanged(float aspectRatio) {
-        for (PinnedStackListener listener : mListeners) {
+        for (PinnedTaskListener listener : mListeners) {
             listener.onAspectRatioChanged(aspectRatio);
         }
     }
 
     @BinderThread
-    private class PinnedStackListenerImpl extends IPinnedStackListener.Stub {
+    private class PinnedTaskListenerImpl extends IPinnedTaskListener.Stub {
         @Override
         public void onMovementBoundsChanged(boolean fromImeAdjustment) {
             mMainExecutor.execute(() -> {
@@ -129,10 +129,10 @@
     }
 
     /**
-     * A counterpart of {@link IPinnedStackListener} with empty implementations.
+     * A counterpart of {@link IPinnedTaskListener} with empty implementations.
      * Subclasses can ignore those methods they do not intend to take action upon.
      */
-    public static class PinnedStackListener {
+    public static class PinnedTaskListener {
         public void onMovementBoundsChanged(boolean fromImeAdjustment) {}
 
         public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index 5ffa988..a52db24 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.pip;
 
+import static android.util.RotationUtils.rotateBounds;
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
 
@@ -33,7 +34,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
 import com.android.wm.shell.animation.Interpolators;
-import com.android.wm.shell.common.DisplayLayout;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -90,15 +90,15 @@
 
     private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
 
-    private PipTransitionAnimator mCurrentAnimator;
-
-    private ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
+    private final ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
             ThreadLocal.withInitial(() -> {
                 AnimationHandler handler = new AnimationHandler();
                 handler.setProvider(new SfVsyncFrameCallbackProvider());
                 return handler;
             });
 
+    private PipTransitionAnimator mCurrentAnimator;
+
     public PipAnimationController(PipSurfaceTransactionHelper helper) {
         mSurfaceTransactionHelper = helper;
     }
@@ -268,6 +268,7 @@
             if (mPipAnimationCallback != null) {
                 mPipAnimationCallback.onPipAnimationEnd(mTaskInfo, tx, this);
             }
+            mTransitionDirection = TRANSITION_DIRECTION_NONE;
         }
 
         @Override
@@ -275,6 +276,7 @@
             if (mPipAnimationCallback != null) {
                 mPipAnimationCallback.onPipAnimationCancel(mTaskInfo, this);
             }
+            mTransitionDirection = TRANSITION_DIRECTION_NONE;
         }
 
         @Override public void onAnimationRepeat(Animator animation) {}
@@ -448,7 +450,7 @@
                 // Rotate the end bounds according to the rotation delta because the display will
                 // be rotated to the same orientation.
                 rotatedEndRect = new Rect(endValue);
-                DisplayLayout.rotateBounds(rotatedEndRect, endValue, rotationDelta);
+                rotateBounds(rotatedEndRect, endValue, rotationDelta);
             } else {
                 rotatedEndRect = null;
             }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
index ac5d14c..702385e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
@@ -54,6 +54,7 @@
     private float mMaxAspectRatio;
     private int mDefaultStackGravity;
     private int mDefaultMinSize;
+    private int mOverridableMinSize;
     private Point mScreenEdgeInsets;
 
     public PipBoundsAlgorithm(Context context, @NonNull PipBoundsState pipBoundsState) {
@@ -78,6 +79,8 @@
                 com.android.internal.R.integer.config_defaultPictureInPictureGravity);
         mDefaultMinSize = res.getDimensionPixelSize(
                 com.android.internal.R.dimen.default_minimal_size_pip_resizable_task);
+        mOverridableMinSize = res.getDimensionPixelSize(
+                com.android.internal.R.dimen.overridable_minimal_size_pip_resizable_task);
         final String screenEdgeInsetsDpString = res.getString(
                 com.android.internal.R.string.config_defaultPictureInPictureScreenEdgeInsets);
         final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty()
@@ -155,7 +158,10 @@
         // -1 will be populated if an activity specifies defaultWidth/defaultHeight in <layout>
         // without minWidth/minHeight
         if (windowLayout.minWidth > 0 && windowLayout.minHeight > 0) {
-            return new Size(windowLayout.minWidth, windowLayout.minHeight);
+            // If either dimension is smaller than the allowed minimum, adjust them
+            // according to mOverridableMinSize
+            return new Size(Math.max(windowLayout.minWidth, mOverridableMinSize),
+                    Math.max(windowLayout.minHeight, mOverridableMinSize));
         }
         return null;
     }
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 4a2a032..9a584c6 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
@@ -65,6 +65,7 @@
 import com.android.wm.shell.pip.PipUtils;
 
 import java.io.PrintWriter;
+import java.util.Objects;
 import java.util.function.Consumer;
 
 /**
@@ -93,17 +94,20 @@
 
     protected PhonePipMenuController mMenuController;
     protected PipTaskOrganizer mPipTaskOrganizer;
-    protected PinnedStackListenerForwarder.PinnedStackListener mPinnedStackListener =
-            new PipControllerPinnedStackListener();
+    protected PinnedStackListenerForwarder.PinnedTaskListener mPinnedTaskListener =
+            new PipControllerPinnedTaskListener();
 
     /**
      * Handler for display rotation changes.
      */
     private final DisplayChangeController.OnDisplayChangingListener mRotationController = (
             int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) -> {
-        if (!mPipTaskOrganizer.isInPip() || mPipTaskOrganizer.isDeferringEnterPipAnimation()) {
-            // Skip if we aren't in PIP or haven't actually entered PIP yet. We still need to update
-            // the display layout in the bounds handler in this case.
+        if (!mPipTaskOrganizer.isInPip()
+                || mPipBoundsState.getDisplayLayout().rotation() == toRotation
+                || mPipTaskOrganizer.isDeferringEnterPipAnimation()) {
+            // Skip if the same rotation has been set or we aren't in PIP or haven't actually
+            // entered PIP yet. We still need to update the display layout in the bounds handler
+            // in this case.
             onDisplayRotationChangedNotInPip(mContext, toRotation);
             // do not forget to update the movement bounds as well.
             updateMovementBounds(mPipBoundsState.getNormalBounds(), true /* fromRotation */,
@@ -178,8 +182,8 @@
     /**
      * Handler for messages from the PIP controller.
      */
-    private class PipControllerPinnedStackListener extends
-            PinnedStackListenerForwarder.PinnedStackListener {
+    private class PipControllerPinnedTaskListener extends
+            PinnedStackListenerForwarder.PinnedTaskListener {
         @Override
         public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
             mPipBoundsState.setImeVisibility(imeVisible, imeHeight);
@@ -310,7 +314,7 @@
         mPipBoundsState.setDisplayLayout(new DisplayLayout(context, context.getDisplay()));
 
         try {
-            mWindowManagerShellWrapper.addPinnedStackListener(mPinnedStackListener);
+            mWindowManagerShellWrapper.addPinnedStackListener(mPinnedTaskListener);
         } catch (RemoteException e) {
             Slog.e(TAG, "Failed to register pinned stack listener", e);
         }
@@ -378,6 +382,9 @@
     }
 
     private void onDisplayChanged(DisplayLayout layout, boolean saveRestoreSnapFraction) {
+        if (Objects.equals(layout, mPipBoundsState.getDisplayLayout())) {
+            return;
+        }
         Runnable updateDisplayLayout = () -> {
             mPipBoundsState.setDisplayLayout(layout);
             updateMovementBounds(null /* toBounds */,
@@ -476,8 +483,11 @@
             int launcherRotation, int shelfHeight) {
         setShelfHeightLocked(shelfHeight > 0 /* visible */, shelfHeight);
         onDisplayRotationChangedNotInPip(mContext, launcherRotation);
-        return mPipTaskOrganizer.startSwipePipToHome(componentName, activityInfo,
+        final Rect entryBounds = mPipTaskOrganizer.startSwipePipToHome(componentName, activityInfo,
                 pictureInPictureParams);
+        // sync mPipBoundsState with the newly calculated bounds.
+        mPipBoundsState.setNormalBounds(entryBounds);
+        return entryBounds;
     }
 
     private void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
index d9a7bdb..9ee6a22 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
@@ -87,7 +87,7 @@
                     SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
 
     // Allow dragging the PIP to a location to close it
-    private final boolean mEnableDismissDragToEdge;
+    private boolean mEnableDismissDragToEdge;
 
     private int mDismissAreaHeight;
 
@@ -104,67 +104,66 @@
         mMotionHelper = motionHelper;
         mMainExecutor = mainExecutor;
         mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+    }
 
-        Resources res = context.getResources();
+    public void init() {
+        Resources res = mContext.getResources();
         mEnableDismissDragToEdge = res.getBoolean(R.bool.config_pipEnableDismissDragToEdge);
         mDismissAreaHeight = res.getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height);
 
-        mMainExecutor.execute(() -> {
-            mTargetView = new DismissCircleView(context);
-            mTargetViewContainer = new FrameLayout(context);
-            mTargetViewContainer.setBackgroundDrawable(
-                    context.getDrawable(R.drawable.floating_dismiss_gradient_transition));
-            mTargetViewContainer.setClipChildren(false);
-            mTargetViewContainer.addView(mTargetView);
+        mTargetView = new DismissCircleView(mContext);
+        mTargetViewContainer = new FrameLayout(mContext);
+        mTargetViewContainer.setBackgroundDrawable(
+                mContext.getDrawable(R.drawable.floating_dismiss_gradient_transition));
+        mTargetViewContainer.setClipChildren(false);
+        mTargetViewContainer.addView(mTargetView);
 
-            mMagnetizedPip = mMotionHelper.getMagnetizedPip();
-            mMagneticTarget = mMagnetizedPip.addTarget(mTargetView, 0);
-            updateMagneticTargetSize();
+        mMagnetizedPip = mMotionHelper.getMagnetizedPip();
+        mMagneticTarget = mMagnetizedPip.addTarget(mTargetView, 0);
+        updateMagneticTargetSize();
 
-            mMagnetizedPip.setAnimateStuckToTarget(
-                    (target, velX, velY, flung, after) -> {
-                        if (mEnableDismissDragToEdge) {
-                            mMotionHelper.animateIntoDismissTarget(target, velX, velY, flung,
-                                    after);
-                        }
-                        return Unit.INSTANCE;
-                    });
-            mMagnetizedPip.setMagnetListener(new MagnetizedObject.MagnetListener() {
-                @Override
-                public void onStuckToTarget(@NonNull MagnetizedObject.MagneticTarget target) {
-                    // Show the dismiss target, in case the initial touch event occurred within
-                    // the magnetic field radius.
+        mMagnetizedPip.setAnimateStuckToTarget(
+                (target, velX, velY, flung, after) -> {
                     if (mEnableDismissDragToEdge) {
-                        showDismissTargetMaybe();
+                        mMotionHelper.animateIntoDismissTarget(target, velX, velY, flung, after);
                     }
+                    return Unit.INSTANCE;
+                });
+        mMagnetizedPip.setMagnetListener(new MagnetizedObject.MagnetListener() {
+            @Override
+            public void onStuckToTarget(@NonNull MagnetizedObject.MagneticTarget target) {
+                // Show the dismiss target, in case the initial touch event occurred within
+                // the magnetic field radius.
+                if (mEnableDismissDragToEdge) {
+                    showDismissTargetMaybe();
                 }
+            }
 
-                @Override
-                public void onUnstuckFromTarget(@NonNull MagnetizedObject.MagneticTarget target,
-                        float velX, float velY, boolean wasFlungOut) {
-                    if (wasFlungOut) {
-                        mMotionHelper.flingToSnapTarget(velX, velY, null /* endAction */);
-                        hideDismissTargetMaybe();
-                    } else {
-                        mMotionHelper.setSpringingToTouch(true);
-                    }
+            @Override
+            public void onUnstuckFromTarget(@NonNull MagnetizedObject.MagneticTarget target,
+                    float velX, float velY, boolean wasFlungOut) {
+                if (wasFlungOut) {
+                    mMotionHelper.flingToSnapTarget(velX, velY, null /* endAction */);
+                    hideDismissTargetMaybe();
+                } else {
+                    mMotionHelper.setSpringingToTouch(true);
                 }
+            }
 
-                @Override
-                public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) {
-                    mMainExecutor.executeDelayed(() -> {
-                        mMotionHelper.notifyDismissalPending();
-                        mMotionHelper.animateDismiss();
-                        hideDismissTargetMaybe();
+            @Override
+            public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) {
+                mMainExecutor.executeDelayed(() -> {
+                    mMotionHelper.notifyDismissalPending();
+                    mMotionHelper.animateDismiss();
+                    hideDismissTargetMaybe();
 
-                        mPipUiEventLogger.log(
-                                PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_DRAG_TO_REMOVE);
-                    }, 0);
-                }
-            });
-
-            mMagneticTargetAnimator = PhysicsAnimator.getInstance(mTargetView);
+                    mPipUiEventLogger.log(
+                            PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_DRAG_TO_REMOVE);
+                }, 0);
+            }
         });
+
+        mMagneticTargetAnimator = PhysicsAnimator.getInstance(mTargetView);
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
index eae8945..d742aa6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
@@ -102,7 +102,7 @@
      * PhysicsAnimator instance for animating {@link PipBoundsState#getMotionBoundsState()}
      * using physics animations.
      */
-    private final PhysicsAnimator<Rect> mTemporaryBoundsPhysicsAnimator;
+    private PhysicsAnimator<Rect> mTemporaryBoundsPhysicsAnimator;
 
     private MagnetizedObject<Rect> mMagnetizedPip;
 
@@ -171,7 +171,7 @@
     public PipMotionHelper(Context context, @NonNull PipBoundsState pipBoundsState,
             PipTaskOrganizer pipTaskOrganizer, PhonePipMenuController menuController,
             PipSnapAlgorithm snapAlgorithm, PipTransitionController pipTransitionController,
-            FloatingContentCoordinator floatingContentCoordinator, ShellExecutor mainExecutor) {
+            FloatingContentCoordinator floatingContentCoordinator) {
         mContext = context;
         mPipTaskOrganizer = pipTaskOrganizer;
         mPipBoundsState = pipBoundsState;
@@ -179,15 +179,6 @@
         mSnapAlgorithm = snapAlgorithm;
         mFloatingContentCoordinator = floatingContentCoordinator;
         pipTransitionController.registerPipTransitionCallback(mPipTransitionCallback);
-        mTemporaryBoundsPhysicsAnimator = PhysicsAnimator.getInstance(
-                mPipBoundsState.getMotionBoundsState().getBoundsInMotion());
-
-        // Need to get the shell main thread sf vsync animation handler
-        mainExecutor.execute(() -> {
-            mTemporaryBoundsPhysicsAnimator.setCustomAnimationHandler(
-                    mSfAnimationHandlerThreadLocal.get());
-        });
-
         mResizePipUpdateListener = (target, values) -> {
             if (mPipBoundsState.getMotionBoundsState().isInMotion()) {
                 mPipTaskOrganizer.scheduleUserResizePip(getBounds(),
@@ -196,6 +187,14 @@
         };
     }
 
+    public void init() {
+        // Note: Needs to get the shell main thread sf vsync animation handler
+        mTemporaryBoundsPhysicsAnimator = PhysicsAnimator.getInstance(
+                mPipBoundsState.getMotionBoundsState().getBoundsInMotion());
+        mTemporaryBoundsPhysicsAnimator.setCustomAnimationHandler(
+                mSfAnimationHandlerThreadLocal.get());
+    }
+
     @NonNull
     @Override
     public Rect getFloatingBoundsOnScreen() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
index 78ee186..31057f8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
@@ -132,8 +132,10 @@
         mUpdateMovementBoundsRunnable = updateMovementBoundsRunnable;
         mPhonePipMenuController = menuActivityController;
         mPipUiEventLogger = pipUiEventLogger;
+    }
 
-        context.getDisplay().getRealSize(mMaxSize);
+    public void init() {
+        mContext.getDisplay().getRealSize(mMaxSize);
         reloadResources();
 
         mEnablePinchResize = DeviceConfig.getBoolean(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 5e23281..543ecfc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -71,12 +71,13 @@
     private static final float DEFAULT_STASH_VELOCITY_THRESHOLD = 18000.f;
 
     // Allow PIP to resize to a slightly bigger state upon touch
-    private final boolean mEnableResize;
+    private boolean mEnableResize;
     private final Context mContext;
     private final PipBoundsAlgorithm mPipBoundsAlgorithm;
     private final @NonNull PipBoundsState mPipBoundsState;
     private final PipUiEventLogger mPipUiEventLogger;
     private final PipDismissTargetHandler mPipDismissTargetHandler;
+    private final ShellExecutor mMainExecutor;
 
     private PipResizeGestureHandler mPipResizeGestureHandler;
     private WeakReference<Consumer<Rect>> mPipExclusionBoundsChangeListener;
@@ -166,16 +167,18 @@
             ShellExecutor mainExecutor) {
         // Initialize the Pip input consumer
         mContext = context;
+        mMainExecutor = mainExecutor;
         mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
         mPipBoundsAlgorithm = pipBoundsAlgorithm;
         mPipBoundsState = pipBoundsState;
         mMenuController = menuController;
         mPipUiEventLogger = pipUiEventLogger;
+        mFloatingContentCoordinator = floatingContentCoordinator;
         mMenuController.addListener(new PipMenuListener());
         mGesture = new DefaultPipTouchGesture();
         mMotionHelper = new PipMotionHelper(mContext, pipBoundsState, pipTaskOrganizer,
                 mMenuController, mPipBoundsAlgorithm.getSnapAlgorithm(), pipTransitionController,
-                floatingContentCoordinator, mainExecutor);
+                floatingContentCoordinator);
         mPipResizeGestureHandler =
                 new PipResizeGestureHandler(context, pipBoundsAlgorithm, pipBoundsState,
                         mMotionHelper, pipTaskOrganizer, this::getMovementBounds,
@@ -199,22 +202,26 @@
                 },
                 menuController::hideMenu,
                 mainExecutor);
-
-        Resources res = context.getResources();
-        mEnableResize = res.getBoolean(R.bool.config_pipEnableResizeForMenu);
-        reloadResources();
-
-        mFloatingContentCoordinator = floatingContentCoordinator;
         mConnection = new PipAccessibilityInteractionConnection(mContext, pipBoundsState,
                 mMotionHelper, pipTaskOrganizer, mPipBoundsAlgorithm.getSnapAlgorithm(),
                 this::onAccessibilityShowMenu, this::updateMovementBounds, mainExecutor);
+    }
+
+    public void init() {
+        Resources res = mContext.getResources();
+        mEnableResize = res.getBoolean(R.bool.config_pipEnableResizeForMenu);
+        reloadResources();
+
+        mMotionHelper.init();
+        mPipResizeGestureHandler.init();
+        mPipDismissTargetHandler.init();
 
         mEnableStash = DeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 PIP_STASHING,
                 /* defaultValue = */ true);
         DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
-                mainExecutor,
+                mMainExecutor,
                 properties -> {
                     if (properties.getKeyset().contains(PIP_STASHING)) {
                         mEnableStash = properties.getBoolean(
@@ -226,7 +233,7 @@
                 PIP_STASH_MINIMUM_VELOCITY_THRESHOLD,
                 DEFAULT_STASH_VELOCITY_THRESHOLD);
         DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
-                mainExecutor,
+                mMainExecutor,
                 properties -> {
                     if (properties.getKeyset().contains(PIP_STASH_MINIMUM_VELOCITY_THRESHOLD)) {
                         mStashVelocityThreshold = properties.getFloat(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
index 56f183f..7098019 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
@@ -377,7 +377,7 @@
 
     private void registerWmShellPinnedStackListener(WindowManagerShellWrapper wmShell) {
         try {
-            wmShell.addPinnedStackListener(new PinnedStackListenerForwarder.PinnedStackListener() {
+            wmShell.addPinnedStackListener(new PinnedStackListenerForwarder.PinnedTaskListener() {
                 @Override
                 public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
                     if (DEBUG) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
index 32f3648..c6d994e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
@@ -280,7 +280,7 @@
                 : stableBounds.right - taskBounds.left - mButtonSize;
         final int positionY = stableBounds.bottom - taskBounds.top - mButtonSize;
 
-        mSyncQueue.runInSync(t -> t.setPosition(leash, positionX, positionY));
+        updateSurfacePosition(leash, positionX, positionY);
     }
 
     void updateHintSurfacePosition() {
@@ -303,7 +303,16 @@
         final int positionY =
                 stableBounds.bottom - taskBounds.top - mPopupOffsetY - mHint.getMeasuredHeight();
 
-        mSyncQueue.runInSync(t -> t.setPosition(leash, positionX, positionY));
+        updateSurfacePosition(leash, positionX, positionY);
+    }
+
+    private void updateSurfacePosition(SurfaceControl leash, int positionX, int positionY) {
+        mSyncQueue.runInSync(t -> {
+            t.setPosition(leash, positionX, positionY);
+            // The size compat UI should be the topmost child of the Task in case there can be more
+            // than one children.
+            t.setLayer(leash, Integer.MAX_VALUE);
+        });
     }
 
     int getDisplayId() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index b0167af..11548ad 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -42,6 +42,7 @@
 
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.DisplayImeController;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.draganddrop.DragAndDropPolicy;
@@ -62,18 +63,20 @@
     private final RootTaskDisplayAreaOrganizer mRootTDAOrganizer;
     private final ShellExecutor mMainExecutor;
     private final SplitScreenImpl mImpl = new SplitScreenImpl();
+    private final DisplayImeController mDisplayImeController;
 
     private StageCoordinator mStageCoordinator;
 
     public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer,
             SyncTransactionQueue syncQueue, Context context,
             RootTaskDisplayAreaOrganizer rootTDAOrganizer,
-            ShellExecutor mainExecutor) {
+            ShellExecutor mainExecutor, DisplayImeController displayImeController) {
         mTaskOrganizer = shellTaskOrganizer;
         mSyncQueue = syncQueue;
         mContext = context;
         mRootTDAOrganizer = rootTDAOrganizer;
         mMainExecutor = mainExecutor;
+        mDisplayImeController = displayImeController;
     }
 
     public SplitScreen asSplitScreen() {
@@ -84,7 +87,7 @@
         if (mStageCoordinator == null) {
             // TODO: Multi-display
             mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
-                    mRootTDAOrganizer, mTaskOrganizer);
+                    mRootTDAOrganizer, mTaskOrganizer, mDisplayImeController);
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index e44c820..bbfbc40 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -39,6 +39,7 @@
 
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.DisplayImeController;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.split.SplitLayout;
 
@@ -79,10 +80,12 @@
     private DisplayAreaInfo mDisplayAreaInfo;
     private final Context mContext;
     private final List<SplitScreen.SplitScreenListener> mListeners = new ArrayList<>();
+    private final DisplayImeController mDisplayImeController;
     private boolean mExitSplitScreenOnHide = true;
 
     StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
-            RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer) {
+            RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
+            DisplayImeController displayImeController) {
         mContext = context;
         mDisplayId = displayId;
         mSyncQueue = syncQueue;
@@ -90,13 +93,14 @@
         mTaskOrganizer = taskOrganizer;
         mMainStage = new MainStage(mTaskOrganizer, mDisplayId, mMainStageListener, mSyncQueue);
         mSideStage = new SideStage(mTaskOrganizer, mDisplayId, mSideStageListener, mSyncQueue);
+        mDisplayImeController = displayImeController;
         mRootTDAOrganizer.registerListener(displayId, this);
     }
 
     @VisibleForTesting
     StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
             RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
-            MainStage mainStage, SideStage sideStage) {
+            MainStage mainStage, SideStage sideStage, DisplayImeController displayImeController) {
         mContext = context;
         mDisplayId = displayId;
         mSyncQueue = syncQueue;
@@ -104,6 +108,7 @@
         mTaskOrganizer = taskOrganizer;
         mMainStage = mainStage;
         mSideStage = sideStage;
+        mDisplayImeController = displayImeController;
         mRootTDAOrganizer.registerListener(displayId, this);
     }
 
@@ -357,8 +362,9 @@
 
     @Override
     public void onSnappedToDismiss(boolean bottomOrRight) {
-        final boolean mainStageToTop = bottomOrRight
-                && mSideStagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT;
+        final boolean mainStageToTop =
+                bottomOrRight ? mSideStagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT
+                        : mSideStagePosition == STAGE_POSITION_TOP_OR_LEFT;
         exitSplitScreen(mainStageToTop ? mMainStage : mSideStage);
     }
 
@@ -420,7 +426,8 @@
         if (mSplitLayout == null) {
             mSplitLayout = new SplitLayout(TAG + "SplitDivider", mContext,
                     mDisplayAreaInfo.configuration, this,
-                    b -> mRootTDAOrganizer.attachToDisplayArea(mDisplayId, b));
+                    b -> mRootTDAOrganizer.attachToDisplayArea(mDisplayId, b),
+                    mDisplayImeController);
         }
     }
 
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 45d5515..7649770 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
@@ -43,6 +43,7 @@
 
 /**
  * Util class to create the view for a splash screen content.
+ *
  * @hide
  */
 public class SplashscreenContentDrawer {
@@ -349,7 +350,7 @@
 
         // Calculate the difference between two colors based on the HSV dimensions.
         final float normalizeH = minAngle / 180f;
-        final double square =  Math.pow(normalizeH, 2)
+        final double square = Math.pow(normalizeH, 2)
                 + Math.pow(aHsv[1] - bHsv[1], 2)
                 + Math.pow(aHsv[2] - bHsv[2], 2);
         final double mean = square / 3;
@@ -433,8 +434,11 @@
          */
         private interface ColorTester {
             float nonTransparentRatio();
+
             boolean isComplexColor();
+
             int getDominantColor();
+
             boolean isGrayscale();
         }
 
@@ -511,14 +515,17 @@
                 // restore to original bounds
                 drawable.setBounds(initialBounds);
 
-                final Palette.Builder builder = new Palette.Builder(bitmap)
-                        .maximumColorCount(5).clearFilters();
+                final Palette.Builder builder;
                 // The Palette API will ignore Alpha, so it cannot handle transparent pixels, but
                 // sometimes we will need this information to know if this Drawable object is
                 // transparent.
                 mFilterTransparent = filterTransparent;
                 if (mFilterTransparent) {
-                    builder.setQuantizer(TRANSPARENT_FILTER_QUANTIZER);
+                    builder = new Palette.Builder(bitmap, TRANSPARENT_FILTER_QUANTIZER)
+                            .maximumColorCount(5);
+                } else {
+                    builder = new Palette.Builder(bitmap, null)
+                            .maximumColorCount(5);
                 }
                 mPalette = builder.generate();
                 bitmap.recycle();
@@ -538,7 +545,7 @@
             public int getDominantColor() {
                 final Palette.Swatch mainSwatch = mPalette.getDominantSwatch();
                 if (mainSwatch != null) {
-                    return mainSwatch.getRgb();
+                    return mainSwatch.getInt();
                 }
                 return Color.BLACK;
             }
@@ -549,7 +556,7 @@
                 if (swatches != null) {
                     for (int i = swatches.size() - 1; i >= 0; i--) {
                         Palette.Swatch swatch = swatches.get(i);
-                        if (!isGrayscaleColor(swatch.getRgb())) {
+                        if (!isGrayscaleColor(swatch.getInt())) {
                             return false;
                         }
                     }
@@ -561,9 +568,9 @@
                 private static final int NON_TRANSPARENT = 0xFF000000;
                 private final Quantizer mInnerQuantizer = new VariationalKMeansQuantizer();
                 private float mNonTransparentRatio;
+
                 @Override
-                public void quantize(final int[] pixels, final int maxColors,
-                        final Palette.Filter[] filters) {
+                public void quantize(final int[] pixels, final int maxColors) {
                     mNonTransparentRatio = 0;
                     int realSize = 0;
                     for (int i = pixels.length - 1; i > 0; i--) {
@@ -575,7 +582,7 @@
                         if (DEBUG) {
                             Slog.d(TAG, "quantize: this is pure transparent image");
                         }
-                        mInnerQuantizer.quantize(pixels, maxColors, filters);
+                        mInnerQuantizer.quantize(pixels, maxColors);
                         return;
                     }
                     mNonTransparentRatio = (float) realSize / pixels.length;
@@ -587,7 +594,7 @@
                             rowIndex++;
                         }
                     }
-                    mInnerQuantizer.quantize(samplePixels, maxColors, filters);
+                    mInnerQuantizer.quantize(samplePixels, maxColors);
                 }
 
                 @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
new file mode 100644
index 0000000..2c4ceff
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.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.wm.shell.startingsurface;
+
+import android.os.IBinder;
+import android.window.StartingWindowInfo;
+
+/**
+ * Interface to engage starting window feature.
+ */
+public interface StartingSurface {
+    /**
+     * Called when a task need a starting window.
+     */
+    void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken);
+    /**
+     * Called when the content of a task is ready to show, starting window can be removed.
+     */
+    void removeStartingWindow(int taskId);
+    /**
+     * Called when the Task wants to copy the splash screen.
+     * @param taskId
+     */
+    void copySplashScreenView(int taskId);
+}
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 5332291..8144071 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
@@ -16,15 +16,9 @@
 
 package com.android.wm.shell.startingsurface;
 
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.content.Context.CONTEXT_RESTRICTED;
 import static android.content.res.Configuration.EMPTY;
 import static android.view.Display.DEFAULT_DISPLAY;
-import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED;
-import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
-import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK;
-import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
-import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
 
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityTaskManager;
@@ -37,7 +31,6 @@
 import android.content.res.TypedArray;
 import android.hardware.display.DisplayManager;
 import android.os.IBinder;
-import android.os.RemoteException;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
@@ -46,7 +39,6 @@
 import android.window.SplashScreenView;
 import android.window.SplashScreenView.SplashScreenViewParcelable;
 import android.window.StartingWindowInfo;
-import android.window.TaskOrganizer;
 import android.window.TaskSnapshot;
 
 import com.android.internal.R;
@@ -56,19 +48,13 @@
 import java.util.function.Consumer;
 
 /**
- * Implementation to draw the starting window to an application, and remove the starting window
- * until the application displays its own window.
- *
- * When receive {@link TaskOrganizer#addStartingWindow} callback, use this class to create a
- * starting window and attached to the Task, then when the Task want to remove the starting window,
- * the TaskOrganizer will receive {@link TaskOrganizer#removeStartingWindow} callback then use this
- * class to remove the starting window of the Task.
+ * A class which able to draw splash screen or snapshot as the starting window for a task.
  * @hide
  */
 public class StartingSurfaceDrawer {
     static final String TAG = StartingSurfaceDrawer.class.getSimpleName();
-    static final boolean DEBUG_SPLASH_SCREEN = false;
-    static final boolean DEBUG_TASK_SNAPSHOT = false;
+    static final boolean DEBUG_SPLASH_SCREEN = StartingWindowController.DEBUG_SPLASH_SCREEN;
+    static final boolean DEBUG_TASK_SNAPSHOT = StartingWindowController.DEBUG_TASK_SNAPSHOT;
 
     private final Context mContext;
     private final DisplayManager mDisplayManager;
@@ -107,106 +93,10 @@
         return context.createDisplayContext(targetDisplay);
     }
 
-    private static class PreferredStartingTypeHelper {
-        private static final int STARTING_TYPE_NO = 0;
-        private static final int STARTING_TYPE_SPLASH_SCREEN = 1;
-        private static final int STARTING_TYPE_SNAPSHOT = 2;
-
-        TaskSnapshot mSnapshot;
-        int mPreferredType;
-
-        PreferredStartingTypeHelper(StartingWindowInfo taskInfo) {
-            final int parameter = taskInfo.startingWindowTypeParameter;
-            final boolean newTask = (parameter & TYPE_PARAMETER_NEW_TASK) != 0;
-            final boolean taskSwitch = (parameter & TYPE_PARAMETER_TASK_SWITCH) != 0;
-            final boolean processRunning = (parameter & TYPE_PARAMETER_PROCESS_RUNNING) != 0;
-            final boolean allowTaskSnapshot = (parameter & TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT) != 0;
-            final boolean activityCreated = (parameter & TYPE_PARAMETER_ACTIVITY_CREATED) != 0;
-            mPreferredType = preferredStartingWindowType(taskInfo, newTask, taskSwitch,
-                    processRunning, allowTaskSnapshot, activityCreated);
-        }
-
-        // reference from ActivityRecord#getStartingWindowType
-        private int preferredStartingWindowType(StartingWindowInfo windowInfo,
-                boolean newTask, boolean taskSwitch, boolean processRunning,
-                boolean allowTaskSnapshot, boolean activityCreated) {
-            if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
-                Slog.d(TAG, "preferredStartingWindowType newTask " + newTask
-                        + " taskSwitch " + taskSwitch
-                        + " processRunning " + processRunning
-                        + " allowTaskSnapshot " + allowTaskSnapshot
-                        + " activityCreated " + activityCreated);
-            }
-
-            if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
-                return STARTING_TYPE_SPLASH_SCREEN;
-            } else if (taskSwitch && allowTaskSnapshot) {
-                final TaskSnapshot snapshot = getTaskSnapshot(windowInfo.taskInfo.taskId);
-                if (isSnapshotCompatible(windowInfo, snapshot)) {
-                    return STARTING_TYPE_SNAPSHOT;
-                }
-                if (windowInfo.taskInfo.topActivityType != ACTIVITY_TYPE_HOME) {
-                    return STARTING_TYPE_SPLASH_SCREEN;
-                }
-                return STARTING_TYPE_NO;
-            } else {
-                return STARTING_TYPE_NO;
-            }
-        }
-
-        /**
-         * Returns {@code true} if the task snapshot is compatible with this activity (at least the
-         * rotation must be the same).
-         */
-        private boolean isSnapshotCompatible(StartingWindowInfo windowInfo, TaskSnapshot snapshot) {
-            if (snapshot == null) {
-                if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
-                    Slog.d(TAG, "isSnapshotCompatible no snapshot " + windowInfo.taskInfo.taskId);
-                }
-                return false;
-            }
-
-            final int taskRotation = windowInfo.taskInfo.configuration
-                    .windowConfiguration.getRotation();
-            final int snapshotRotation = snapshot.getRotation();
-            if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
-                Slog.d(TAG, "isSnapshotCompatible rotation " + taskRotation
-                        + " snapshot " + snapshotRotation);
-            }
-            return taskRotation == snapshotRotation;
-        }
-
-        private TaskSnapshot getTaskSnapshot(int taskId) {
-            if (mSnapshot != null) {
-                return mSnapshot;
-            }
-            try {
-                mSnapshot = ActivityTaskManager.getService().getTaskSnapshot(taskId,
-                        false/* isLowResolution */);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Unable to get snapshot for task: " + taskId + ", from: " + e);
-                return null;
-            }
-            return mSnapshot;
-        }
-    }
-
     /**
-     * Called when a task need a starting window.
+     * Called when a task need a splash screen starting window.
      */
-    public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
-        final PreferredStartingTypeHelper helper =
-                new PreferredStartingTypeHelper(windowInfo);
-        if (helper.mPreferredType == PreferredStartingTypeHelper.STARTING_TYPE_SPLASH_SCREEN) {
-            addSplashScreenStartingWindow(windowInfo, appToken);
-        } else if (helper.mPreferredType == PreferredStartingTypeHelper.STARTING_TYPE_SNAPSHOT) {
-            final TaskSnapshot snapshot = helper.mSnapshot;
-            makeTaskSnapshotWindow(windowInfo, appToken, snapshot);
-        }
-        // If prefer don't show, then don't show!
-    }
-
-    private void addSplashScreenStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
+    public void addSplashScreenStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
         final RunningTaskInfo taskInfo = windowInfo.taskInfo;
         final ActivityInfo activityInfo = taskInfo.topActivityInfo;
         if (activityInfo == null) {
@@ -378,8 +268,8 @@
     /**
      * Called when a task need a snapshot starting window.
      */
-    private void makeTaskSnapshotWindow(StartingWindowInfo startingWindowInfo,
-            IBinder appToken, TaskSnapshot snapshot) {
+    void makeTaskSnapshotWindow(StartingWindowInfo startingWindowInfo, IBinder appToken,
+            TaskSnapshot snapshot) {
         final int taskId = startingWindowInfo.taskInfo.taskId;
         final TaskSnapshotWindow surface = TaskSnapshotWindow.create(startingWindowInfo, appToken,
                 snapshot, mMainExecutor, () -> removeWindowSynced(taskId) /* clearWindow */);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
new file mode 100644
index 0000000..73bf8ac
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
@@ -0,0 +1,196 @@
+/*
+ * 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.wm.shell.startingsurface;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_NONE;
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SNAPSHOT;
+import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
+
+import android.app.ActivityTaskManager;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.window.StartingWindowInfo;
+import android.window.TaskOrganizer;
+import android.window.TaskSnapshot;
+
+import com.android.wm.shell.common.ShellExecutor;
+
+/**
+ * Implementation to draw the starting window to an application, and remove the starting window
+ * until the application displays its own window.
+ *
+ * When receive {@link TaskOrganizer#addStartingWindow} callback, use this class to create a
+ * starting window and attached to the Task, then when the Task want to remove the starting window,
+ * the TaskOrganizer will receive {@link TaskOrganizer#removeStartingWindow} callback then use this
+ * class to remove the starting window of the Task.
+ * @hide
+ */
+public class StartingWindowController {
+    private static final String TAG = StartingWindowController.class.getSimpleName();
+    static final boolean DEBUG_SPLASH_SCREEN = false;
+    static final boolean DEBUG_TASK_SNAPSHOT = false;
+
+    private final StartingSurfaceDrawer mStartingSurfaceDrawer;
+    private final StartingTypeChecker mStartingTypeChecker = new StartingTypeChecker();
+    private final StartingSurfaceImpl mImpl = new StartingSurfaceImpl();
+
+    public StartingWindowController(Context context, ShellExecutor mainExecutor) {
+        mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, mainExecutor);
+    }
+
+    /**
+     * Provide the implementation for Shell Module.
+     */
+    public StartingSurface asStartingSurface() {
+        return mImpl;
+    }
+
+    private static class StartingTypeChecker {
+        TaskSnapshot mSnapshot;
+
+        StartingTypeChecker() { }
+
+        private void reset() {
+            mSnapshot = null;
+        }
+
+        private @StartingWindowInfo.StartingWindowType int
+                estimateStartingWindowType(StartingWindowInfo windowInfo) {
+            reset();
+            final int parameter = windowInfo.startingWindowTypeParameter;
+            final boolean newTask = (parameter & TYPE_PARAMETER_NEW_TASK) != 0;
+            final boolean taskSwitch = (parameter & TYPE_PARAMETER_TASK_SWITCH) != 0;
+            final boolean processRunning = (parameter & TYPE_PARAMETER_PROCESS_RUNNING) != 0;
+            final boolean allowTaskSnapshot = (parameter & TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT) != 0;
+            final boolean activityCreated = (parameter & TYPE_PARAMETER_ACTIVITY_CREATED) != 0;
+            return estimateStartingWindowType(windowInfo, newTask, taskSwitch,
+                    processRunning, allowTaskSnapshot, activityCreated);
+        }
+
+        // reference from ActivityRecord#getStartingWindowType
+        private int estimateStartingWindowType(StartingWindowInfo windowInfo,
+                boolean newTask, boolean taskSwitch, boolean processRunning,
+                boolean allowTaskSnapshot, boolean activityCreated) {
+            if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+                Slog.d(TAG, "preferredStartingWindowType newTask " + newTask
+                        + " taskSwitch " + taskSwitch
+                        + " processRunning " + processRunning
+                        + " allowTaskSnapshot " + allowTaskSnapshot
+                        + " activityCreated " + activityCreated);
+            }
+            if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
+                return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+            }
+            if (taskSwitch && allowTaskSnapshot) {
+                final TaskSnapshot snapshot = getTaskSnapshot(windowInfo.taskInfo.taskId);
+                if (isSnapshotCompatible(windowInfo, snapshot)) {
+                    return STARTING_WINDOW_TYPE_SNAPSHOT;
+                }
+                if (windowInfo.taskInfo.topActivityType != ACTIVITY_TYPE_HOME) {
+                    return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+                }
+            }
+            return STARTING_WINDOW_TYPE_NONE;
+        }
+
+        /**
+         * Returns {@code true} if the task snapshot is compatible with this activity (at least the
+         * rotation must be the same).
+         */
+        private boolean isSnapshotCompatible(StartingWindowInfo windowInfo, TaskSnapshot snapshot) {
+            if (snapshot == null) {
+                if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+                    Slog.d(TAG, "isSnapshotCompatible no snapshot " + windowInfo.taskInfo.taskId);
+                }
+                return false;
+            }
+
+            final int taskRotation = windowInfo.taskInfo.configuration
+                    .windowConfiguration.getRotation();
+            final int snapshotRotation = snapshot.getRotation();
+            if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+                Slog.d(TAG, "isSnapshotCompatible rotation " + taskRotation
+                        + " snapshot " + snapshotRotation);
+            }
+            return taskRotation == snapshotRotation;
+        }
+
+        private TaskSnapshot getTaskSnapshot(int taskId) {
+            if (mSnapshot != null) {
+                return mSnapshot;
+            }
+            try {
+                mSnapshot = ActivityTaskManager.getService().getTaskSnapshot(taskId,
+                        false/* isLowResolution */);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Unable to get snapshot for task: " + taskId + ", from: " + e);
+                return null;
+            }
+            return mSnapshot;
+        }
+    }
+
+    /**
+     * Called when a task need a starting window.
+     */
+    void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
+        final int suggestionType = mStartingTypeChecker.estimateStartingWindowType(windowInfo);
+        if (suggestionType == STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
+            mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken);
+        } else if (suggestionType == STARTING_WINDOW_TYPE_SNAPSHOT) {
+            final TaskSnapshot snapshot = mStartingTypeChecker.mSnapshot;
+            mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, appToken, snapshot);
+        }
+        // If prefer don't show, then don't show!
+    }
+
+    void copySplashScreenView(int taskId) {
+        mStartingSurfaceDrawer.copySplashScreenView(taskId);
+    }
+
+    /**
+     * Called when the content of a task is ready to show, starting window can be removed.
+     */
+    void removeStartingWindow(int taskId) {
+        mStartingSurfaceDrawer.removeStartingWindow(taskId);
+    }
+
+    private class StartingSurfaceImpl implements StartingSurface {
+
+        @Override
+        public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
+            StartingWindowController.this.addStartingWindow(windowInfo, appToken);
+        }
+
+        @Override
+        public void removeStartingWindow(int taskId) {
+            StartingWindowController.this.removeStartingWindow(taskId);
+        }
+
+        @Override
+        public void copySplashScreenView(int taskId) {
+            StartingWindowController.this.copySplashScreenView(taskId);
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp
index a57ac35..9dd25fe 100644
--- a/libs/WindowManager/Shell/tests/flicker/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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_test {
     name: "WMShellFlickerTests",
     srcs: ["src/**/*.java", "src/**/*.kt"],
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
index 10aea51..35bab7a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
@@ -18,8 +18,6 @@
 
 import android.graphics.Region
 import android.view.Surface
-import com.android.server.wm.flicker.APP_PAIR_SPLIT_DIVIDER
-import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.server.wm.flicker.traces.layers.getVisibleBounds
@@ -32,15 +30,15 @@
 
 fun FlickerTestParameter.appPairsDividerIsInvisible() {
     assertLayersEnd {
-        this.notExists(APP_PAIR_SPLIT_DIVIDER)
+        this.notContains(APP_PAIR_SPLIT_DIVIDER)
     }
 }
 
 fun FlickerTestParameter.appPairsDividerBecomesVisible() {
     assertLayers {
-        this.hidesLayer(DOCKED_STACK_DIVIDER)
+        this.isInvisible(DOCKED_STACK_DIVIDER)
             .then()
-            .showsLayer(DOCKED_STACK_DIVIDER)
+            .isVisible(DOCKED_STACK_DIVIDER)
     }
 }
 
@@ -52,30 +50,30 @@
 
 fun FlickerTestParameter.dockedStackDividerBecomesVisible() {
     assertLayers {
-        this.hidesLayer(DOCKED_STACK_DIVIDER)
+        this.isInvisible(DOCKED_STACK_DIVIDER)
             .then()
-            .showsLayer(DOCKED_STACK_DIVIDER)
+            .isVisible(DOCKED_STACK_DIVIDER)
     }
 }
 
 fun FlickerTestParameter.dockedStackDividerBecomesInvisible() {
     assertLayers {
-        this.showsLayer(DOCKED_STACK_DIVIDER)
+        this.isVisible(DOCKED_STACK_DIVIDER)
             .then()
-            .hidesLayer(DOCKED_STACK_DIVIDER)
+            .isInvisible(DOCKED_STACK_DIVIDER)
     }
 }
 
 fun FlickerTestParameter.dockedStackDividerIsInvisible() {
     assertLayersEnd {
-        this.notExists(DOCKED_STACK_DIVIDER)
+        this.notContains(DOCKED_STACK_DIVIDER)
     }
 }
 
 fun FlickerTestParameter.appPairsPrimaryBoundsIsVisible(rotation: Int, primaryLayerName: String) {
     assertLayersEnd {
         val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
-        this.hasVisibleRegion(primaryLayerName, getPrimaryRegion(dividerRegion, rotation))
+        this.coversExactly(getPrimaryRegion(dividerRegion, rotation), primaryLayerName)
     }
 }
 
@@ -85,7 +83,7 @@
 ) {
     assertLayersEnd {
         val dividerRegion = entry.getVisibleBounds(DOCKED_STACK_DIVIDER)
-        this.hasVisibleRegion(primaryLayerName, getPrimaryRegion(dividerRegion, rotation))
+        this.coversExactly(getPrimaryRegion(dividerRegion, rotation), primaryLayerName)
     }
 }
 
@@ -95,7 +93,7 @@
 ) {
     assertLayersEnd {
         val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
-        this.hasVisibleRegion(secondaryLayerName, getSecondaryRegion(dividerRegion, rotation))
+        this.coversExactly(getSecondaryRegion(dividerRegion, rotation), secondaryLayerName)
     }
 }
 
@@ -105,7 +103,7 @@
 ) {
     assertLayersEnd {
         val dividerRegion = entry.getVisibleBounds(DOCKED_STACK_DIVIDER)
-        this.hasVisibleRegion(secondaryLayerName, getSecondaryRegion(dividerRegion, rotation))
+        this.coversExactly(getSecondaryRegion(dividerRegion, rotation), secondaryLayerName)
     }
 }
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
index d2cfb0f..03b93c7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
@@ -18,3 +18,5 @@
 
 const val IME_WINDOW_NAME = "InputMethod"
 const val SYSTEM_UI_PACKAGE_NAME = "com.android.systemui"
+const val APP_PAIR_SPLIT_DIVIDER = "AppPairSplitDivider"
+const val DOCKED_STACK_DIVIDER = "DockedStackDivider"
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
index 5d51b2f..90e7137 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.apppairs
 
-import android.os.Bundle
 import android.os.SystemClock
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.RequiresDevice
@@ -48,7 +47,7 @@
     testSpec: FlickerTestParameter
 ) : AppPairsTransition(testSpec) {
 
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = {
             super.transition(this, it)
             transitions {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
index 77890ba..dc51b4f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
@@ -16,17 +16,16 @@
 
 package com.android.wm.shell.flicker.apppairs
 
-import android.os.Bundle
 import android.os.SystemClock
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.APP_PAIR_SPLIT_DIVIDER
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.traces.layers.getVisibleBounds
+import com.android.wm.shell.flicker.APP_PAIR_SPLIT_DIVIDER
 import com.android.wm.shell.flicker.appPairsDividerIsVisible
 import com.android.wm.shell.flicker.helpers.AppPairsHelper
 import org.junit.FixMethodOrder
@@ -46,7 +45,7 @@
 class AppPairsTestPairPrimaryAndSecondaryApps(
     testSpec: FlickerTestParameter
 ) : AppPairsTransition(testSpec) {
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = {
             super.transition(this, it)
             transitions {
@@ -75,10 +74,10 @@
     fun appsEndingBounds() {
         testSpec.assertLayersEnd {
             val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
-            this.hasVisibleRegion(primaryApp.defaultWindowName,
-                appPairsHelper.getPrimaryBounds(dividerRegion))
-                .hasVisibleRegion(secondaryApp.defaultWindowName,
-                    appPairsHelper.getSecondaryBounds(dividerRegion))
+            this.coversExactly(appPairsHelper.getPrimaryBounds(dividerRegion),
+                primaryApp.defaultWindowName)
+                .coversExactly(appPairsHelper.getSecondaryBounds(dividerRegion),
+                    secondaryApp.defaultWindowName)
         }
     }
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
index 3d3ca0c..5bb9b2f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
@@ -16,17 +16,16 @@
 
 package com.android.wm.shell.flicker.apppairs
 
-import android.os.Bundle
 import android.os.SystemClock
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.APP_PAIR_SPLIT_DIVIDER
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.traces.layers.getVisibleBounds
+import com.android.wm.shell.flicker.APP_PAIR_SPLIT_DIVIDER
 import com.android.wm.shell.flicker.appPairsDividerIsInvisible
 import com.android.wm.shell.flicker.helpers.AppPairsHelper
 import org.junit.FixMethodOrder
@@ -46,7 +45,7 @@
 class AppPairsTestUnpairPrimaryAndSecondaryApps(
     testSpec: FlickerTestParameter
 ) : AppPairsTransition(testSpec) {
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = {
             super.transition(this, it)
             setup {
@@ -80,10 +79,10 @@
     fun appsStartingBounds() {
         testSpec.assertLayersStart {
             val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
-            hasVisibleRegion(primaryApp.defaultWindowName,
-                appPairsHelper.getPrimaryBounds(dividerRegion))
-            hasVisibleRegion(secondaryApp.defaultWindowName,
-                appPairsHelper.getSecondaryBounds(dividerRegion))
+            coversExactly(appPairsHelper.getPrimaryBounds(dividerRegion),
+                primaryApp.defaultWindowName)
+            coversExactly(appPairsHelper.getSecondaryBounds(dividerRegion),
+                secondaryApp.defaultWindowName)
         }
     }
 
@@ -91,8 +90,8 @@
     @Test
     fun appsEndingBounds() {
         testSpec.assertLayersEnd {
-            notExists(primaryApp.defaultWindowName)
-            notExists(secondaryApp.defaultWindowName)
+            notContains(primaryApp.defaultWindowName)
+            notContains(secondaryApp.defaultWindowName)
         }
     }
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
index 9e6752d..91e080f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
@@ -17,7 +17,6 @@
 package com.android.wm.shell.flicker.apppairs
 
 import android.app.Instrumentation
-import android.os.Bundle
 import android.platform.test.annotations.Presubmit
 import android.system.helpers.ActivityHelper
 import android.util.Log
@@ -66,7 +65,7 @@
         }
     }
 
-    internal open val transition: FlickerBuilder.(Bundle) -> Unit
+    internal open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             setup {
                 test {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
index 35a0020..5f003ba 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.apppairs
 
-import android.os.Bundle
 import android.os.SystemClock
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
@@ -52,7 +51,7 @@
 class RotateTwoLaunchedAppsInAppPairsMode(
     testSpec: FlickerTestParameter
 ) : RotateTwoLaunchedAppsTransition(testSpec) {
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = {
             super.transition(this, it)
             transitions {
@@ -72,16 +71,16 @@
         }
     }
 
-    @FlakyTest
+    @Presubmit
     @Test
     fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible()
 
-    @FlakyTest
+    @Presubmit
     @Test
     fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0,
         testSpec.config.endRotation)
 
-    @FlakyTest
+    @Presubmit
     @Test
     fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0,
         testSpec.config.endRotation)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
index 326a775..d479208 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.apppairs
 
-import android.os.Bundle
 import android.os.SystemClock
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
@@ -55,7 +54,7 @@
 class RotateTwoLaunchedAppsRotateAndEnterAppPairsMode(
     testSpec: FlickerTestParameter
 ) : RotateTwoLaunchedAppsTransition(testSpec) {
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = {
             super.transition(this, it)
             transitions {
@@ -77,17 +76,8 @@
 
     @Presubmit
     @Test
-    fun navBarLayerRotatesAndScales() {
-        Assume.assumeFalse(isRotated)
-        testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
-    }
-
-    @FlakyTest
-    @Test
-    fun navBarLayerRotatesAndScales_Flaky() {
-        Assume.assumeTrue(isRotated)
-        testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
-    }
+    fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales(
+        Surface.ROTATION_0, testSpec.config.endRotation)
 
     @Presubmit
     @Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
index 271b25f..83853e6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.apppairs
 
-import android.os.Bundle
 import android.view.Surface
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.dsl.FlickerBuilder
@@ -30,7 +29,7 @@
     override val nonResizeableApp: SplitScreenHelper?
         get() = null
 
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = {
             setup {
                 test {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
index 9b70fac..17c51fb 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
-import android.os.Bundle
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -50,11 +49,10 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-// @FlakyTest(bugId = 179116910)
 class EnterSplitScreenDockActivity(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenTransition(testSpec) {
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             super.transition(this, configuration)
             transitions {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
index bd57a59..a94fd46 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
-import android.os.Bundle
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -54,7 +53,7 @@
 class EnterSplitScreenLaunchToSide(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenTransition(testSpec) {
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             super.transition(this, configuration)
             transitions {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNonResizableNotDock.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNonResizableNotDock.kt
index 67578b2..238059b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNonResizableNotDock.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNonResizableNotDock.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
-import android.os.Bundle
 import android.view.Surface
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
@@ -50,7 +49,7 @@
 class EnterSplitScreenNonResizableNotDock(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenTransition(testSpec) {
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             super.transition(this, configuration)
             teardown {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
index 5d42a4a..acd570a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
@@ -16,12 +16,10 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
-import android.os.Bundle
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
@@ -34,6 +32,7 @@
 import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
 import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -52,7 +51,7 @@
 class ExitLegacySplitScreenFromBottom(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenTransition(testSpec) {
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             super.transition(this, configuration)
             setup {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
index ff8f9c6..cef1886 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
-import android.os.Bundle
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -53,7 +52,7 @@
 class ExitPrimarySplitScreenShowSecondaryFullscreen(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenTransition(testSpec) {
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             super.transition(this, configuration)
             teardown {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt
index 893b101..1e89a25 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
-import android.os.Bundle
 import android.view.Surface
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.dsl.FlickerBuilder
@@ -27,7 +26,7 @@
 abstract class LegacySplitScreenRotateTransition(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenTransition(testSpec) {
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = {
             setup {
                 eachRun {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
index 09a7e31..7f69a66 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
-import android.os.Bundle
 import android.platform.test.annotations.Presubmit
 import android.support.test.launcherhelper.LauncherStrategyFactory
 import android.view.Surface
@@ -66,7 +65,7 @@
         .launcherStrategy.supportedLauncherPackage
     private val testApp = SimpleAppHelper(instrumentation)
 
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             setup {
                 test {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
index 6ab1f0b..91ea871 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
@@ -17,7 +17,6 @@
 package com.android.wm.shell.flicker.legacysplitscreen
 
 import android.app.Instrumentation
-import android.os.Bundle
 import android.support.test.launcherhelper.LauncherStrategyFactory
 import android.view.Surface
 import androidx.test.platform.app.InstrumentationRegistry
@@ -41,7 +40,7 @@
     protected val LAUNCHER_PACKAGE_NAME = LauncherStrategyFactory.getInstance(instrumentation)
         .launcherStrategy.supportedLauncherPackage
 
-    protected open val transition: FlickerBuilder.(Bundle) -> Unit
+    protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             setup {
                 eachRun {
@@ -70,7 +69,7 @@
         }
     }
 
-    internal open val cleanSetup: FlickerBuilder.(Bundle) -> Unit
+    internal open val cleanSetup: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             setup {
                 eachRun {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreen.kt
index 1b4b54a..caafa27 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreen.kt
@@ -16,12 +16,10 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
-import android.os.Bundle
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
@@ -34,6 +32,7 @@
 import com.android.server.wm.flicker.layerBecomesVisible
 import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
 import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -53,7 +52,7 @@
 class NonResizableDismissInLegacySplitScreen(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenTransition(testSpec) {
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             cleanSetup(this, configuration)
             setup {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreen.kt
index 2365e3b..543484a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreen.kt
@@ -16,12 +16,10 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
-import android.os.Bundle
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
@@ -33,6 +31,7 @@
 import com.android.server.wm.flicker.layerBecomesVisible
 import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
 import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -53,7 +52,7 @@
 class NonResizableLaunchInLegacySplitScreen(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenTransition(testSpec) {
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             cleanSetup(this, configuration)
             setup {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
index b369a3d..d228337 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
-import android.os.Bundle
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -53,7 +52,7 @@
 class OpenAppToLegacySplitScreen(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenTransition(testSpec) {
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             super.transition(this, configuration)
             transitions {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
index ffffa19..f5174bc 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
@@ -17,13 +17,11 @@
 package com.android.wm.shell.flicker.legacysplitscreen
 
 import android.graphics.Region
-import android.os.Bundle
 import android.util.Rational
 import android.view.Surface
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import androidx.test.uiautomator.By
-import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
@@ -46,6 +44,7 @@
 import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
 import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import com.android.server.wm.flicker.traces.layers.getVisibleBounds
+import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER
 import com.android.wm.shell.flicker.helpers.SimpleAppHelper
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -70,7 +69,7 @@
     private val testAppTop = SimpleAppHelper(instrumentation)
     private val testAppBottom = ImeAppHelper(instrumentation)
 
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             setup {
                 eachRun {
@@ -151,21 +150,21 @@
     @Test
     fun topAppLayerIsAlwaysVisible() {
         testSpec.assertLayers {
-            this.showsLayer(sSimpleActivity)
+            this.isVisible(sSimpleActivity)
         }
     }
 
     @Test
     fun bottomAppLayerIsAlwaysVisible() {
         testSpec.assertLayers {
-            this.showsLayer(sImeActivity)
+            this.isVisible(sImeActivity)
         }
     }
 
     @Test
     fun dividerLayerIsAlwaysVisible() {
         testSpec.assertLayers {
-            this.showsLayer(DOCKED_STACK_DIVIDER)
+            this.isVisible(DOCKED_STACK_DIVIDER)
         }
     }
 
@@ -183,8 +182,8 @@
                 dividerBounds.bottom - WindowUtils.dockedStackDividerInset,
                 displayBounds.right,
                 displayBounds.bottom - WindowUtils.navigationBarHeight)
-            this.hasVisibleRegion("SimpleActivity", topAppBounds)
-                .hasVisibleRegion("ImeActivity", bottomAppBounds)
+            this.coversExactly(topAppBounds, "SimpleActivity")
+                .coversExactly(bottomAppBounds, "ImeActivity")
         }
     }
 
@@ -203,8 +202,8 @@
                 displayBounds.right,
                 displayBounds.bottom - WindowUtils.navigationBarHeight)
 
-            this.hasVisibleRegion(sSimpleActivity, topAppBounds)
-                .hasVisibleRegion(sImeActivity, bottomAppBounds)
+            this.coversExactly(topAppBounds, sSimpleActivity)
+                .coversExactly(bottomAppBounds, sImeActivity)
         }
     }
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
index c538008..c914ada 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
-import android.os.Bundle
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -54,7 +53,7 @@
 class RotateOneLaunchedAppAndEnterSplitScreen(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenRotateTransition(testSpec) {
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             super.transition(this, configuration)
             transitions {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
index c116256..ffb20a4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
-import android.os.Bundle
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -54,7 +53,7 @@
 class RotateOneLaunchedAppInSplitScreenMode(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenRotateTransition(testSpec) {
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             super.transition(this, configuration)
             transitions {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
index 273925c..8cf1990 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
-import android.os.Bundle
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -56,7 +55,7 @@
 class RotateTwoLaunchedAppAndEnterSplitScreen(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenRotateTransition(testSpec) {
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             super.transition(this, configuration)
             transitions {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
index c7188dc..9c798d8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
-import android.os.Bundle
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -56,7 +55,7 @@
 class RotateTwoLaunchedAppInSplitScreenMode(
     testSpec: FlickerTestParameter
 ) : LegacySplitScreenRotateTransition(testSpec) {
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             super.transition(this, configuration)
             setup {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
index ca48eaa..75c33c6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.os.Bundle
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.RequiresDevice
@@ -51,7 +50,7 @@
     private val testApp = FixedAppHelper(instrumentation)
     private val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
 
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = buildTransition(eachRun = true) {
             setup {
                 eachRun {
@@ -68,7 +67,7 @@
     @Test
     fun pipAppRemainInsideVisibleBounds() {
         testSpec.assertWm {
-            coversAtMostRegion(pipApp.defaultWindowName, displayBounds)
+            coversAtMost(displayBounds, pipApp.defaultWindowName)
         }
     }
 
@@ -95,10 +94,10 @@
     @Test
     fun showBothAppLayersThenHidePip() {
         testSpec.assertLayers {
-            showsLayer(testApp.defaultWindowName)
-                .showsLayer(pipApp.defaultWindowName)
+            isVisible(testApp.defaultWindowName)
+                .isVisible(pipApp.defaultWindowName)
                 .then()
-                .hidesLayer(testApp.defaultWindowName)
+                .isInvisible(testApp.defaultWindowName)
         }
     }
 
@@ -106,8 +105,8 @@
     @Test
     fun testAppCoversFullScreenWithPipOnDisplay() {
         testSpec.assertLayersStart {
-            hasVisibleRegion(testApp.defaultWindowName, displayBounds)
-            coversAtMostRegion(displayBounds, pipApp.defaultWindowName)
+            coversExactly(displayBounds, testApp.defaultWindowName)
+            coversAtMost(displayBounds, pipApp.defaultWindowName)
         }
     }
 
@@ -115,7 +114,7 @@
     @Test
     fun pipAppCoversFullScreen() {
         testSpec.assertLayersEnd {
-            hasVisibleRegion(pipApp.defaultWindowName, displayBounds)
+            coversExactly(displayBounds, pipApp.defaultWindowName)
         }
     }
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index e1fbc16..83dca53 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.os.Bundle
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -48,7 +47,7 @@
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = buildTransition(eachRun = true, stringExtras = emptyMap()) {
             transitions {
                 pipApp.clickEnterPipButton()
@@ -85,7 +84,7 @@
     @Test
     fun pipLayerBecomesVisible() {
         testSpec.assertLayers {
-            this.showsLayer(pipApp.launcherName)
+            this.isVisible(pipApp.launcherName)
         }
     }
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
index 215b97b..9011f1a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
@@ -16,10 +16,8 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.os.Bundle
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
-import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
@@ -56,7 +54,7 @@
     private val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90)
     private val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0)
 
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             setupAndTeardown(this, configuration)
 
@@ -121,24 +119,24 @@
     @Test
     fun pipAppLayerHidesTestApp() {
         testSpec.assertLayersStart {
-            hasVisibleRegion(pipApp.defaultWindowName, startingBounds)
+            coversExactly(startingBounds, pipApp.defaultWindowName)
             isInvisible(testApp.defaultWindowName)
         }
     }
 
-    @FlakyTest
+    @Presubmit
     @Test
     fun testAppLayerCoversFullScreen() {
         testSpec.assertLayersEnd {
-            hasVisibleRegion(testApp.defaultWindowName, endingBounds)
+            coversExactly(endingBounds, testApp.defaultWindowName)
         }
     }
 
-    @FlakyTest(bugId = 140855415)
+    @Presubmit
     @Test
     fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
 
-    @FlakyTest(bugId = 140855415)
+    @Presubmit
     @Test
     fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/Extensions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/Extensions.kt
index 707d28d..96eb66c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/Extensions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/Extensions.kt
@@ -48,7 +48,7 @@
     activity: ComponentName
 ): WindowManagerStateSubject = apply {
     val windowName = activity.toWindowName()
-    hasWindow(windowName)
+    contains(windowName)
     val pinnedWindows = wmState.pinnedWindows
         .map { it.title }
     Truth.assertWithMessage("Window not in PIP mode")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt
similarity index 63%
rename from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToHomeTest.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt
index 968a11d..3e33176 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 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.
@@ -16,41 +16,27 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.os.Bundle
-import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.focusChanges
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
 import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
 import com.android.server.wm.flicker.noUncoveredRegions
 import com.android.server.wm.flicker.startRotation
 import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
 import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import org.junit.FixMethodOrder
 import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
 import org.junit.runners.Parameterized
 
-/**
- * Test Pip launch.
- * To run this test: `atest WMShellFlickerTests:PipToHomeTest`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class PipToHomeTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+abstract class PipCloseTransition(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = buildTransition(eachRun = true) { configuration ->
             setup {
                 eachRun {
@@ -62,30 +48,27 @@
                     this.setRotation(Surface.ROTATION_0)
                 }
             }
-            transitions {
-                pipApp.closePipWindow(wmHelper)
-            }
         }
 
-    @Postsubmit
+    @Presubmit
     @Test
-    fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+    open fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
 
     @Presubmit
     @Test
-    fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+    open fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
 
     @Presubmit
     @Test
-    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+    open fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
 
     @Presubmit
     @Test
-    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    open fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
 
     @Presubmit
     @Test
-    fun pipWindowBecomesInvisible() {
+    open fun pipWindowBecomesInvisible() {
         testSpec.assertWm {
             this.showsAppWindow(PIP_WINDOW_TITLE)
                 .then()
@@ -95,32 +78,32 @@
 
     @Presubmit
     @Test
-    fun pipLayerBecomesInvisible() {
+    open fun pipLayerBecomesInvisible() {
         testSpec.assertLayers {
-            this.showsLayer(PIP_WINDOW_TITLE)
+            this.isVisible(PIP_WINDOW_TITLE)
                 .then()
-                .hidesLayer(PIP_WINDOW_TITLE)
+                .isInvisible(PIP_WINDOW_TITLE)
         }
     }
 
     @Presubmit
     @Test
-    fun statusBarLayerRotatesScales() =
+    open fun statusBarLayerRotatesScales() =
         testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
 
-    @Postsubmit
+    @Presubmit
     @Test
-    fun noUncoveredRegions() =
+    open fun noUncoveredRegions() =
         testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0)
 
-    @Postsubmit
+    @Presubmit
     @Test
-    fun navBarLayerRotatesAndScales() =
-        testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0)
+    open fun navBarLayerRotatesAndScales() =
+        testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
 
     @FlakyTest(bugId = 151179149)
     @Test
-    fun focusChanges() = testSpec.focusChanges(pipApp.launcherName, "NexusLauncherActivity")
+    open fun focusChanges() = testSpec.focusChanges(pipApp.launcherName, "NexusLauncherActivity")
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt
new file mode 100644
index 0000000..0408421
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt
@@ -0,0 +1,44 @@
+/*
+ * 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.wm.shell.flicker.pip
+
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip launch.
+ * To run this test: `atest WMShellFlickerTests:PipCloseWithDismissButton`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class PipCloseWithDismissButtonTest(testSpec: FlickerTestParameter) : PipCloseTransition(testSpec) {
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+        get() = {
+            super.transition(this, it)
+            transitions {
+                pipApp.closePipWindow(wmHelper)
+            }
+        }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt
new file mode 100644
index 0000000..afaf33a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.pip
+
+import android.platform.test.annotations.Postsubmit
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip launch.
+ * To run this test: `atest WMShellFlickerTests:PipCloseWithSwipe`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class PipCloseWithSwipeTest(testSpec: FlickerTestParameter) : PipCloseTransition(testSpec) {
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+        get() = {
+            super.transition(this, it)
+            transitions {
+                val pipRegion = wmHelper.getWindowRegion(pipApp.component).bounds
+                val pipCenterX = pipRegion.centerX()
+                val pipCenterY = pipRegion.centerY()
+                val displayCenterX = device.displayWidth / 2
+                device.swipe(pipCenterX, pipCenterY, displayCenterX, device.displayHeight, 5)
+            }
+        }
+
+    @Postsubmit
+    @Test
+    override fun navBarLayerIsAlwaysVisible() = super.navBarLayerIsAlwaysVisible()
+
+    @Postsubmit
+    @Test
+    override fun statusBarLayerIsAlwaysVisible() = super.statusBarLayerIsAlwaysVisible()
+
+    @Postsubmit
+    @Test
+    override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
+
+    @Postsubmit
+    @Test
+    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
+
+    @Postsubmit
+    @Test
+    override fun pipWindowBecomesInvisible() = super.pipWindowBecomesInvisible()
+
+    @Postsubmit
+    @Test
+    override fun pipLayerBecomesInvisible() = super.pipLayerBecomesInvisible()
+
+    @Postsubmit
+    @Test
+    override fun statusBarLayerRotatesScales() =
+        testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+
+    @Postsubmit
+    @Test
+    override fun noUncoveredRegions() = super.noUncoveredRegions()
+
+    @Postsubmit
+    @Test
+    override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
index f3b9ea1..4633960 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.os.Bundle
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.RequiresDevice
@@ -46,7 +45,7 @@
 class PipKeyboardTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
     private val imeApp = ImeAppHelper(instrumentation)
 
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = buildTransition(eachRun = false) { configuration ->
             setup {
                 test {
@@ -78,7 +77,7 @@
     fun pipInVisibleBounds() {
         testSpec.assertWm {
             val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
-            coversAtMostRegion(pipApp.defaultWindowName, displayBounds)
+            coversAtMost(displayBounds, pipApp.defaultWindowName)
         }
     }
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
index daf381e..97afc65 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.os.Bundle
 import android.platform.test.annotations.Postsubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -58,7 +57,7 @@
     private val testApp = FixedAppHelper(instrumentation)
     private val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
 
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = {
             withTestName { testSpec.name }
             repeat { testSpec.config.repetitions }
@@ -90,7 +89,7 @@
     @Test
     fun pipWindowInsideDisplayBounds() {
         testSpec.assertWm {
-            coversAtMostRegion(pipApp.defaultWindowName, displayBounds)
+            coversAtMost(displayBounds, pipApp.defaultWindowName)
         }
     }
 
@@ -100,7 +99,7 @@
         testSpec.assertWmEnd {
             isVisible(testApp.defaultWindowName)
             isVisible(imeApp.defaultWindowName)
-            noWindowsOverlap(setOf(testApp.defaultWindowName, imeApp.defaultWindowName))
+            noWindowsOverlap(testApp.defaultWindowName, imeApp.defaultWindowName)
         }
     }
 
@@ -116,7 +115,7 @@
     @Test
     fun pipLayerInsideDisplayBounds() {
         testSpec.assertLayers {
-            coversAtMostRegion(displayBounds, pipApp.defaultWindowName)
+            coversAtMost(displayBounds, pipApp.defaultWindowName)
         }
     }
 
@@ -124,8 +123,8 @@
     @Test
     fun bothAppLayersVisible() {
         testSpec.assertLayersEnd {
-            coversAtMostRegion(displayBounds, testApp.defaultWindowName)
-            coversAtMostRegion(displayBounds, imeApp.defaultWindowName)
+            coversAtMost(displayBounds, testApp.defaultWindowName)
+            coversAtMost(displayBounds, imeApp.defaultWindowName)
         }
     }
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipMovesInAllApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipMovesInAllApps.kt
new file mode 100644
index 0000000..4c95da2
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipMovesInAllApps.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.pip
+
+import android.platform.test.annotations.Postsubmit
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.google.common.truth.Truth
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip launch.
+ * To run this test: `atest WMShellFlickerTests:PipMovesInAllApps`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class PipMovesInAllApps(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+    private val taplInstrumentation = LauncherInstrumentation()
+
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+        get() = buildTransition(eachRun = false) {
+            teardown {
+                eachRun {
+                    taplInstrumentation.pressHome()
+                }
+            }
+            transitions {
+                taplInstrumentation.pressHome().switchToAllApps()
+                wmHelper.waitForAppTransitionIdle()
+            }
+        }
+
+    @Postsubmit
+    @Test
+    fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+    @Postsubmit
+    @Test
+    fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+    @Postsubmit
+    @Test
+    fun pipAlwaysVisible() = testSpec.assertWm { this.showsAppWindow(pipApp.windowName) }
+
+    @Postsubmit
+    @Test
+    fun pipWindowMovesUp() = testSpec.assertWmEnd {
+        val initialState = this.trace?.first()?.wmState
+            ?: error("Trace should not be empty")
+        val startPos = initialState.pinnedWindows.first().frame
+        val currPos = this.wmState.pinnedWindows.first().frame
+        val subject = Truth.assertWithMessage("Pip should have moved up")
+        subject.that(currPos.top).isGreaterThan(startPos.top)
+        subject.that(currPos.bottom).isGreaterThan(startPos.bottom)
+        subject.that(currPos.left).isEqualTo(startPos.left)
+        subject.that(currPos.right).isEqualTo(startPos.right)
+    }
+
+    companion object {
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun getParams(): List<FlickerTestParameter> {
+            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
+                supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5)
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
index 43c12ac..df835d2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.os.Bundle
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -56,7 +55,7 @@
     private val startingBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
     private val endingBounds = WindowUtils.getDisplayBounds(testSpec.config.endRotation)
 
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = buildTransition(eachRun = false) { configuration ->
             setup {
                 test {
@@ -89,11 +88,11 @@
     fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
         testSpec.config.endRotation, allStates = false)
 
-    @FlakyTest(bugId = 140855415)
+    @Presubmit
     @Test
     fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
 
-    @FlakyTest(bugId = 140855415)
+    @Presubmit
     @Test
     fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
 
@@ -113,8 +112,8 @@
     @Test
     fun appLayerRotates_StartingBounds() {
         testSpec.assertLayersStart {
-            hasVisibleRegion(fixedApp.defaultWindowName, startingBounds)
-            coversAtMostRegion(startingBounds, pipApp.defaultWindowName)
+            coversExactly(startingBounds, fixedApp.defaultWindowName)
+            coversAtMost(startingBounds, pipApp.defaultWindowName)
         }
     }
 
@@ -122,8 +121,8 @@
     @Test
     fun appLayerRotates_EndingBounds() {
         testSpec.assertLayersEnd {
-            hasVisibleRegion(fixedApp.defaultWindowName, endingBounds)
-            coversAtMostRegion(endingBounds, pipApp.defaultWindowName)
+            coversExactly(endingBounds, fixedApp.defaultWindowName)
+            coversAtMost(endingBounds, pipApp.defaultWindowName)
         }
     }
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
index 02389a9..1bb1d28 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.os.Bundle
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -50,7 +49,7 @@
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 class PipToAppTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = buildTransition(eachRun = true) { configuration ->
             setup {
                 eachRun {
@@ -67,7 +66,7 @@
             }
         }
 
-    @FlakyTest(bugId = 140855415)
+    @Presubmit
     @Test
     fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
 
@@ -102,18 +101,18 @@
     @Test
     fun appReplacesPipLayer() {
         testSpec.assertLayers {
-            this.showsLayer(PIP_WINDOW_TITLE)
+            this.isVisible(PIP_WINDOW_TITLE)
                 .then()
-                .showsLayer(pipApp.launcherName)
+                .isVisible(pipApp.launcherName)
         }
     }
 
-    @FlakyTest
+    @Presubmit
     @Test
     fun noUncoveredRegions() =
         testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0)
 
-    @FlakyTest(bugId = 140855415)
+    @Presubmit
     @Test
     fun navBarLayerRotatesAndScales() =
         testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
index a94483e..b0a9afe 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
@@ -18,7 +18,6 @@
 
 import android.app.Instrumentation
 import android.content.Intent
-import android.os.Bundle
 import android.view.Surface
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.wm.flicker.FlickerBuilderProvider
@@ -38,7 +37,7 @@
     protected val isRotated = testSpec.config.startRotation.isRotated()
     protected val pipApp = PipAppHelper(instrumentation)
     protected val broadcastActionTrigger = BroadcastActionTrigger(instrumentation)
-    protected abstract val transition: FlickerBuilder.(Bundle) -> Unit
+    protected abstract val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
 
     // Helper class to process test actions by broadcast.
     protected class BroadcastActionTrigger(private val instrumentation: Instrumentation) {
@@ -81,7 +80,7 @@
     /**
      * Gets a configuration that handles basic setup and teardown of pip tests
      */
-    protected val setupAndTeardown: FlickerBuilder.(Bundle) -> Unit
+    protected val setupAndTeardown: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = {
             setup {
                 test {
@@ -112,8 +111,8 @@
     protected open fun buildTransition(
         eachRun: Boolean,
         stringExtras: Map<String, String> = mapOf(Components.PipActivity.EXTRA_ENTER_PIP to "true"),
-        extraSpec: FlickerBuilder.(Bundle) -> Unit = {}
-    ): FlickerBuilder.(Bundle) -> Unit {
+        extraSpec: FlickerBuilder.(Map<String, Any?>) -> Unit = {}
+    ): FlickerBuilder.(Map<String, Any?>) -> Unit {
         return { configuration ->
             setupAndTeardown(this, configuration)
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
index 1f0370d..7916ce5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.os.Bundle
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -54,7 +53,7 @@
     private val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0)
     private val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90)
 
-    override val transition: FlickerBuilder.(Bundle) -> Unit
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = { configuration ->
             setupAndTeardown(this, configuration)
 
@@ -88,7 +87,7 @@
     @Test
     fun pipWindowInsideDisplay() {
         testSpec.assertWmStart {
-            coversAtMostRegion(pipApp.defaultWindowName, startingBounds)
+            coversAtMost(startingBounds, pipApp.defaultWindowName)
         }
     }
 
@@ -112,7 +111,7 @@
     @Test
     fun pipLayerInsideDisplay() {
         testSpec.assertLayersStart {
-            coversAtMostRegion(startingBounds, pipApp.defaultWindowName)
+            coversAtMost(startingBounds, pipApp.defaultWindowName)
         }
     }
 
@@ -120,15 +119,15 @@
     @Test
     fun pipAppLayerCoversFullScreen() {
         testSpec.assertLayersEnd {
-            hasVisibleRegion(pipApp.defaultWindowName, endingBounds)
+            coversExactly(endingBounds, pipApp.defaultWindowName)
         }
     }
 
-    @FlakyTest(bugId = 140855415)
+    @Presubmit
     @Test
     fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
 
-    @FlakyTest(bugId = 140855415)
+    @Presubmit
     @Test
     fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
 
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp
index 26627a4..ea606df 100644
--- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+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_test {
     name: "WMShellFlickerTestApp",
     srcs: ["**/*.java"],
@@ -23,4 +32,4 @@
     name: "wmshell-flicker-test-components",
     srcs: ["src/**/Components.java"],
     sdk_version: "test_current",
-}
\ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
index a0e9f43..06b492d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
@@ -53,7 +53,6 @@
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.sizecompatui.SizeCompatUIController;
-import com.android.wm.shell.startingsurface.StartingSurfaceDrawer;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -79,8 +78,6 @@
     private Context mContext;
     @Mock
     private SizeCompatUIController mSizeCompatUI;
-    @Mock
-    private StartingSurfaceDrawer mStartingSurfaceDrawer;
 
     ShellTaskOrganizer mOrganizer;
     private final SyncTransactionQueue mSyncTransactionQueue = mock(SyncTransactionQueue.class);
@@ -116,7 +113,7 @@
                     .when(mTaskOrganizerController).registerTaskOrganizer(any());
         } catch (RemoteException e) {}
         mOrganizer = spy(new ShellTaskOrganizer(mTaskOrganizerController, mTestExecutor, mContext,
-                mSizeCompatUI, mStartingSurfaceDrawer));
+                mSizeCompatUI));
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java
index e094158..27c6261 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java
@@ -20,17 +20,17 @@
 
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayImeController;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 
-import org.mockito.Mock;
-
 public class TestAppPairsController extends AppPairsController {
     private TestAppPairsPool mPool;
 
     public TestAppPairsController(ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue,
             DisplayController displayController) {
-        super(organizer, syncQueue, displayController, mock(ShellExecutor.class));
+        super(organizer, syncQueue, displayController, mock(ShellExecutor.class),
+                mock(DisplayImeController.class));
         mPool = new TestAppPairsPool(this);
         setPairsPool(mPool);
     }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java
index 2b5b77e..88e754c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java
@@ -38,6 +38,12 @@
 
 import org.junit.Test;
 
+/**
+ * Tests for {@link DisplayLayout}.
+ *
+ * Build/Install/Run:
+ *  atest WMShellUnitTests:DisplayLayoutTest
+ */
 @SmallTest
 public class DisplayLayoutTest {
 
@@ -70,18 +76,6 @@
     @Test
     public void testRotate() {
         // Basic rotate utility
-        Rect testParent = new Rect(0, 0, 1000, 600);
-        Rect testInner = new Rect(40, 20, 120, 80);
-        Rect testResult = new Rect(testInner);
-        DisplayLayout.rotateBounds(testResult, testParent, 1);
-        assertEquals(new Rect(20, 880, 80, 960), testResult);
-        testResult.set(testInner);
-        DisplayLayout.rotateBounds(testResult, testParent, 2);
-        assertEquals(new Rect(880, 20, 960, 80), testResult);
-        testResult.set(testInner);
-        DisplayLayout.rotateBounds(testResult, testParent, 3);
-        assertEquals(new Rect(520, 40, 580, 120), testResult);
-
         Resources res = createResources(40, 50, false, 30, 40);
         DisplayInfo info = createDisplayInfo(1000, 1500, 60, ROTATION_0);
         DisplayLayout dl = new DisplayLayout(info, res, true, true);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java
index 21bc32c..d8aebc2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java
@@ -198,7 +198,7 @@
 
     @Test
     public void testOnActivityDismissingDockedStack() {
-        mImpl.onActivityDismissingDockedStack();
+        mImpl.onActivityDismissingDockedTask();
         verify(mCallback).onActivityDismissingDockedStack();
         verify(mOtherCallback).onActivityDismissingDockedStack();
     }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
index 5821eed..7b0e6b9 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
@@ -36,6 +36,7 @@
 
 import com.android.internal.policy.DividerSnapAlgorithm;
 import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.common.DisplayImeController;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -49,6 +50,7 @@
 public class SplitLayoutTests extends ShellTestCase {
     @Mock SplitLayout.LayoutChangeListener mLayoutChangeListener;
     @Mock SurfaceControl mRootLeash;
+    @Mock DisplayImeController mDisplayImeController;
     private SplitLayout mSplitLayout;
 
     @Before
@@ -59,7 +61,8 @@
                 mContext,
                 getConfiguration(false),
                 mLayoutChangeListener,
-                b -> b.setParent(mRootLeash));
+                b -> b.setParent(mRootLeash),
+                mDisplayImeController);
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
index 698315a..86d0d82 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
@@ -29,6 +29,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.common.DisplayImeController;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -42,6 +43,7 @@
 public class SplitWindowManagerTests extends ShellTestCase {
     @Mock SurfaceControl mSurfaceControl;
     @Mock SplitLayout mSplitLayout;
+    @Mock DisplayImeController mDisplayImeController;
     private SplitWindowManager mSplitWindowManager;
 
     @Before
@@ -50,7 +52,7 @@
         final Configuration configuration = new Configuration();
         configuration.setToDefaults();
         mSplitWindowManager = new SplitWindowManager("TestSplitDivider", mContext, configuration,
-                b -> b.setParent(mSurfaceControl));
+                b -> b.setParent(mSurfaceControl), mDisplayImeController);
         when(mSplitLayout.getDividerBounds()).thenReturn(
                 new Rect(0, 0, configuration.windowConfiguration.getBounds().width(),
                         configuration.windowConfiguration.getBounds().height()));
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 3147dab..63b9413 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
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.pip;
 
+import static android.util.RotationUtils.rotateBounds;
 import static android.view.Surface.ROTATION_0;
 import static android.view.Surface.ROTATION_90;
 
@@ -37,7 +38,6 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.common.DisplayLayout;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -141,7 +141,7 @@
         // Apply fraction 1 to compute the end value.
         animator.applySurfaceControlTransaction(mLeash, new DummySurfaceControlTx(), 1);
         final Rect rotatedEndBounds = new Rect(endBounds);
-        DisplayLayout.rotateBounds(rotatedEndBounds, endBounds, ROTATION_90);
+        rotateBounds(rotatedEndBounds, endBounds, ROTATION_90);
 
         assertEquals("Expect 90 degree rotated bounds", rotatedEndBounds, animator.mCurrentValue);
     }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index d10c036..79ec624 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -43,7 +43,6 @@
 import com.android.wm.shell.TestShellExecutor;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
 import com.android.wm.shell.pip.phone.PhonePipMenuController;
 
@@ -125,7 +124,7 @@
 
     @Test
     public void startSwipePipToHome_updatesOverrideMinSize() {
-        final Size minSize = new Size(100, 80);
+        final Size minSize = new Size(400, 320);
 
         mSpiedPipTaskOrganizer.startSwipePipToHome(mComponent1, createActivityInfo(minSize),
                 createPipParams(null));
@@ -153,7 +152,7 @@
 
     @Test
     public void onTaskAppeared_updatesOverrideMinSize() {
-        final Size minSize = new Size(100, 80);
+        final Size minSize = new Size(400, 320);
 
         mSpiedPipTaskOrganizer.onTaskAppeared(
                 createTaskInfo(mComponent1, createPipParams(null), minSize),
@@ -191,7 +190,7 @@
         mSpiedPipTaskOrganizer.onTaskAppeared(createTaskInfo(mComponent1,
                 createPipParams(null)), null /* leash */);
 
-        final Size minSize = new Size(100, 80);
+        final Size minSize = new Size(400, 320);
         mSpiedPipTaskOrganizer.onTaskInfoChanged(createTaskInfo(mComponent2,
                 createPipParams(null), minSize));
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index cfe8463..f2b4e97 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -124,7 +124,7 @@
         final ComponentName component1 = new ComponentName(mContext, "component1");
         when(mMockPipBoundsState.getLastPipComponentName()).thenReturn(component1);
 
-        mPipController.mPinnedStackListener.onActivityHidden(component1);
+        mPipController.mPinnedTaskListener.onActivityHidden(component1);
 
         verify(mMockPipBoundsState).setLastPipComponentName(null);
     }
@@ -135,7 +135,7 @@
         final ComponentName component2 = new ComponentName(mContext, "component2");
         when(mMockPipBoundsState.getLastPipComponentName()).thenReturn(component1);
 
-        mPipController.mPinnedStackListener.onActivityHidden(component2);
+        mPipController.mPinnedTaskListener.onActivityHidden(component2);
 
         verify(mMockPipBoundsState, never()).setLastPipComponentName(null);
     }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
index 19930485..75ea4ac 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
@@ -106,6 +106,7 @@
                 mPipBoundsAlgorithm, mPipBoundsState, mPipTaskOrganizer,
                 mMockPipTransitionController, mFloatingContentCoordinator, mPipUiEventLogger,
                 mMainExecutor);
+        mPipTouchHandler.init();
         mMotionHelper = Mockito.spy(mPipTouchHandler.getMotionHelper());
         mPipResizeGestureHandler = Mockito.spy(mPipTouchHandler.getPipResizeGestureHandler());
         mPipTouchHandler.setPipMotionHelper(mMotionHelper);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index d2d1812..74753aa 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -41,6 +41,7 @@
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.TestRunningTaskInfoBuilder;
+import com.android.wm.shell.common.DisplayImeController;
 import com.android.wm.shell.common.SyncTransactionQueue;
 
 import org.junit.Before;
@@ -58,13 +59,14 @@
     @Mock private RootTaskDisplayAreaOrganizer mRootTDAOrganizer;
     @Mock private MainStage mMainStage;
     @Mock private SideStage mSideStage;
+    @Mock private DisplayImeController mDisplayImeController;
     private StageCoordinator mStageCoordinator;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
         mStageCoordinator = new TestStageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
-                mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage);
+                mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage, mDisplayImeController);
     }
 
     @Test
@@ -94,9 +96,9 @@
 
         TestStageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
                 RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
-                MainStage mainStage, SideStage sideStage) {
+                MainStage mainStage, SideStage sideStage, DisplayImeController imeController) {
             super(context, displayId, syncQueue, rootTDAOrganizer, taskOrganizer, mainStage,
-                    sideStage);
+                    sideStage, imeController);
 
             // Prepare default TaskDisplayArea for testing.
             mDisplayAreaInfo = new DisplayAreaInfo(
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index de7d6c7..b9af9ce 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -125,7 +125,7 @@
         final Handler mainLoop = new Handler(Looper.getMainLooper());
         final StartingWindowInfo windowInfo =
                 createWindowInfo(taskId, android.R.style.Theme);
-        mStartingSurfaceDrawer.addStartingWindow(windowInfo, mBinder);
+        mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder);
         waitHandlerIdle(mainLoop);
         verify(mStartingSurfaceDrawer).postAddWindow(
                 eq(taskId), eq(mBinder), any(), any(), any(), any());
@@ -143,7 +143,7 @@
         final Handler mainLoop = new Handler(Looper.getMainLooper());
         final StartingWindowInfo windowInfo =
                 createWindowInfo(taskId, 0);
-        mStartingSurfaceDrawer.addStartingWindow(windowInfo, mBinder);
+        mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder);
         waitHandlerIdle(mainLoop);
         verify(mStartingSurfaceDrawer).postAddWindow(
                 eq(taskId), eq(mBinder), any(), any(), any(), any());
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index 9c743ce..76366fc 100755
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -156,7 +156,11 @@
                                                   std::move(loaded_idmap)));
 }
 
-const std::string& ApkAssets::GetPath() const {
+std::optional<std::string_view> ApkAssets::GetPath() const {
+  return assets_provider_->GetPath();
+}
+
+const std::string& ApkAssets::GetDebugName() const {
   return assets_provider_->GetDebugName();
 }
 
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 36bde5c..c0ef7be 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -116,8 +116,10 @@
   package_groups_.clear();
   package_ids_.fill(0xff);
 
-  // A mapping from apk assets path to the runtime package id of its first loaded package.
-  std::unordered_map<std::string, uint8_t> apk_assets_package_ids;
+  // A mapping from path of apk assets that could be target packages of overlays to the runtime
+  // package id of its first loaded package. Overlays currently can only override resources in the
+  // first package in the target resource table.
+  std::unordered_map<std::string, uint8_t> target_assets_package_ids;
 
   // Overlay resources are not directly referenced by an application so their resource ids
   // can change throughout the application's lifetime. Assign overlay package ids last.
@@ -140,8 +142,8 @@
     if (auto loaded_idmap = apk_assets->GetLoadedIdmap(); loaded_idmap != nullptr) {
       // The target package must precede the overlay package in the apk assets paths in order
       // to take effect.
-      auto iter = apk_assets_package_ids.find(std::string(loaded_idmap->TargetApkPath()));
-      if (iter == apk_assets_package_ids.end()) {
+      auto iter = target_assets_package_ids.find(std::string(loaded_idmap->TargetApkPath()));
+      if (iter == target_assets_package_ids.end()) {
          LOG(INFO) << "failed to find target package for overlay "
                    << loaded_idmap->OverlayApkPath();
       } else {
@@ -205,7 +207,10 @@
             package_name, static_cast<uint8_t>(entry.package_id));
       }
 
-      apk_assets_package_ids.insert(std::make_pair(apk_assets->GetPath(), package_id));
+      if (auto apk_assets_path = apk_assets->GetPath()) {
+        // Overlay target ApkAssets must have been created using path based load apis.
+        target_assets_package_ids.insert(std::make_pair(std::string(*apk_assets_path), package_id));
+      }
     }
   }
 
@@ -227,7 +232,7 @@
 
   std::string list;
   for (const auto& apk_assets : apk_assets_) {
-    base::StringAppendF(&list, "%s,", apk_assets->GetPath().c_str());
+    base::StringAppendF(&list, "%s,", apk_assets->GetDebugName().c_str());
   }
   LOG(INFO) << "ApkAssets: " << list;
 
@@ -383,8 +388,8 @@
   }
 }
 
-std::set<std::string> AssetManager2::GetNonSystemOverlayPaths() const {
-  std::set<std::string> non_system_overlays;
+std::set<const ApkAssets*> AssetManager2::GetNonSystemOverlays() const {
+  std::set<const ApkAssets*> non_system_overlays;
   for (const PackageGroup& package_group : package_groups_) {
     bool found_system_package = false;
     for (const ConfiguredPackage& package : package_group.packages_) {
@@ -396,7 +401,7 @@
 
     if (!found_system_package) {
       for (const ConfiguredOverlay& overlay : package_group.overlays_) {
-        non_system_overlays.insert(apk_assets_[overlay.cookie]->GetPath());
+        non_system_overlays.insert(apk_assets_[overlay.cookie]);
       }
     }
   }
@@ -408,7 +413,7 @@
     bool exclude_system, bool exclude_mipmap) const {
   ATRACE_NAME("AssetManager::GetResourceConfigurations");
   const auto non_system_overlays =
-      (exclude_system) ? GetNonSystemOverlayPaths() : std::set<std::string>();
+      (exclude_system) ? GetNonSystemOverlays() : std::set<const ApkAssets*>();
 
   std::set<ResTable_config> configurations;
   for (const PackageGroup& package_group : package_groups_) {
@@ -419,8 +424,8 @@
       }
 
       auto apk_assets = apk_assets_[package_group.cookies_[i]];
-      if (exclude_system && apk_assets->IsOverlay()
-          && non_system_overlays.find(apk_assets->GetPath()) == non_system_overlays.end()) {
+      if (exclude_system && apk_assets->IsOverlay() &&
+          non_system_overlays.find(apk_assets) == non_system_overlays.end()) {
         // Exclude overlays that target system resources.
         continue;
       }
@@ -439,7 +444,7 @@
   ATRACE_NAME("AssetManager::GetResourceLocales");
   std::set<std::string> locales;
   const auto non_system_overlays =
-      (exclude_system) ? GetNonSystemOverlayPaths() : std::set<std::string>();
+      (exclude_system) ? GetNonSystemOverlays() : std::set<const ApkAssets*>();
 
   for (const PackageGroup& package_group : package_groups_) {
     for (size_t i = 0; i < package_group.packages_.size(); i++) {
@@ -449,8 +454,8 @@
       }
 
       auto apk_assets = apk_assets_[package_group.cookies_[i]];
-      if (exclude_system && apk_assets->IsOverlay()
-          && non_system_overlays.find(apk_assets->GetPath()) == non_system_overlays.end()) {
+      if (exclude_system && apk_assets->IsOverlay() &&
+          non_system_overlays.find(apk_assets) == non_system_overlays.end()) {
         // Exclude overlays that target system resources.
         continue;
       }
@@ -491,7 +496,7 @@
       AssetDir::FileInfo info;
       info.setFileName(String8(name.data(), name.size()));
       info.setFileType(type);
-      info.setSourceName(String8(apk_assets->GetPath().c_str()));
+      info.setSourceName(String8(apk_assets->GetDebugName().c_str()));
       files->add(info);
     };
 
@@ -846,7 +851,7 @@
     }
 
     log_stream << "\n\t" << prefix->second << ": " << *step.package_name << " ("
-               << apk_assets_[step.cookie]->GetPath() << ")";
+               << apk_assets_[step.cookie]->GetDebugName() << ")";
     if (!step.config_name.isEmpty()) {
       log_stream << " -" << step.config_name;
     }
@@ -1556,41 +1561,32 @@
     std::map<ApkAssetsCookie, SourceToDestinationRuntimePackageMap> src_asset_cookie_id_map;
 
     // Determine which ApkAssets are loaded in both theme AssetManagers.
-    std::vector<const ApkAssets*> src_assets = o.asset_manager_->GetApkAssets();
+    const auto src_assets = o.asset_manager_->GetApkAssets();
     for (size_t i = 0; i < src_assets.size(); i++) {
       const ApkAssets* src_asset = src_assets[i];
 
-      std::vector<const ApkAssets*> dest_assets = asset_manager_->GetApkAssets();
+      const auto dest_assets = asset_manager_->GetApkAssets();
       for (size_t j = 0; j < dest_assets.size(); j++) {
         const ApkAssets* dest_asset = dest_assets[j];
-
-        // Map the runtime package of the source apk asset to the destination apk asset.
-        if (src_asset->GetPath() == dest_asset->GetPath()) {
-          const auto& src_packages = src_asset->GetLoadedArsc()->GetPackages();
-          const auto& dest_packages = dest_asset->GetLoadedArsc()->GetPackages();
-
-          SourceToDestinationRuntimePackageMap package_map;
-
-          // The source and destination package should have the same number of packages loaded in
-          // the same order.
-          const size_t N = src_packages.size();
-          CHECK(N == dest_packages.size())
-              << " LoadedArsc " << src_asset->GetPath() << " differs number of packages.";
-          for (size_t p = 0; p < N; p++) {
-            auto& src_package = src_packages[p];
-            auto& dest_package = dest_packages[p];
-            CHECK(src_package->GetPackageName() == dest_package->GetPackageName())
-                << " Package " << src_package->GetPackageName() << " differs in load order.";
-
-            int src_package_id = o.asset_manager_->GetAssignedPackageId(src_package.get());
-            int dest_package_id = asset_manager_->GetAssignedPackageId(dest_package.get());
-            package_map[src_package_id] = dest_package_id;
-          }
-
-          src_to_dest_asset_cookies.insert(std::make_pair(i, j));
-          src_asset_cookie_id_map.insert(std::make_pair(i, package_map));
-          break;
+        if (src_asset != dest_asset) {
+          // ResourcesManager caches and reuses ApkAssets when the same apk must be present in
+          // multiple AssetManagers. Two ApkAssets point to the same version of the same resources
+          // if they are the same instance.
+          continue;
         }
+
+        // Map the package ids of the asset in the source AssetManager to the package ids of the
+        // asset in th destination AssetManager.
+        SourceToDestinationRuntimePackageMap package_map;
+        for (const auto& loaded_package : src_asset->GetLoadedArsc()->GetPackages()) {
+          const int src_package_id = o.asset_manager_->GetAssignedPackageId(loaded_package.get());
+          const int dest_package_id = asset_manager_->GetAssignedPackageId(loaded_package.get());
+          package_map[src_package_id] = dest_package_id;
+        }
+
+        src_to_dest_asset_cookies.insert(std::make_pair(i, j));
+        src_asset_cookie_id_map.insert(std::make_pair(i, package_map));
+        break;
       }
     }
 
diff --git a/libs/androidfw/AssetsProvider.cpp b/libs/androidfw/AssetsProvider.cpp
index f3c48f7..0aaf0b3 100644
--- a/libs/androidfw/AssetsProvider.cpp
+++ b/libs/androidfw/AssetsProvider.cpp
@@ -261,6 +261,13 @@
   return entry.crc32;
 }
 
+std::optional<std::string_view> ZipAssetsProvider::GetPath() const {
+  if (name_.GetPath() != nullptr) {
+    return *name_.GetPath();
+  }
+  return {};
+}
+
 const std::string& ZipAssetsProvider::GetDebugName() const {
   return name_.GetDebugName();
 }
@@ -318,6 +325,10 @@
   return true;
 }
 
+std::optional<std::string_view> DirectoryAssetsProvider::GetPath() const {
+  return dir_;
+}
+
 const std::string& DirectoryAssetsProvider::GetDebugName() const {
   return dir_;
 }
@@ -336,13 +347,9 @@
                                          std::unique_ptr<AssetsProvider>&& secondary)
                       : primary_(std::forward<std::unique_ptr<AssetsProvider>>(primary)),
                         secondary_(std::forward<std::unique_ptr<AssetsProvider>>(secondary)) {
-  if (primary_->GetDebugName() == kEmptyDebugString) {
-    debug_name_ = secondary_->GetDebugName();
-  } else if (secondary_->GetDebugName() == kEmptyDebugString) {
-    debug_name_ = primary_->GetDebugName();
-  } else {
-    debug_name_ = primary_->GetDebugName() + " and " + secondary_->GetDebugName();
-  }
+  debug_name_ = primary_->GetDebugName() + " and " + secondary_->GetDebugName();
+  path_ = (primary_->GetDebugName() != kEmptyDebugString) ? primary_->GetPath()
+                                                          : secondary_->GetPath();
 }
 
 std::unique_ptr<AssetsProvider> MultiAssetsProvider::Create(
@@ -367,6 +374,10 @@
   return primary_->ForEachFile(root_path, f) && secondary_->ForEachFile(root_path, f);
 }
 
+std::optional<std::string_view> MultiAssetsProvider::GetPath() const {
+  return path_;
+}
+
 const std::string& MultiAssetsProvider::GetDebugName() const {
   return debug_name_;
 }
@@ -394,6 +405,10 @@
   return true;
 }
 
+std::optional<std::string_view> EmptyAssetsProvider::GetPath() const {
+  return {};
+}
+
 const std::string& EmptyAssetsProvider::GetDebugName() const {
   const static std::string kEmpty = kEmptyDebugString;
   return kEmpty;
diff --git a/libs/androidfw/fuzz/cursorwindow_fuzzer/Android.bp b/libs/androidfw/fuzz/cursorwindow_fuzzer/Android.bp
index b36ff09..3035a79 100644
--- a/libs/androidfw/fuzz/cursorwindow_fuzzer/Android.bp
+++ b/libs/androidfw/fuzz/cursorwindow_fuzzer/Android.bp
@@ -1,3 +1,12 @@
+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_libs_androidfw_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_libs_androidfw_license"],
+}
+
 cc_fuzz {
     name: "cursorwindow_fuzzer",
     srcs: [
diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h
index d0019ed..6f88f41 100644
--- a/libs/androidfw/include/androidfw/ApkAssets.h
+++ b/libs/androidfw/include/androidfw/ApkAssets.h
@@ -34,7 +34,6 @@
 // Holds an APK.
 class ApkAssets {
  public:
-
   // Creates an ApkAssets from a path on device.
   static std::unique_ptr<ApkAssets> Load(const std::string& path,
                                          package_property_t flags = 0U);
@@ -61,12 +60,11 @@
   static std::unique_ptr<ApkAssets> LoadOverlay(const std::string& idmap_path,
                                                 package_property_t flags = 0U);
 
-  // TODO(177101983): Remove all uses of GetPath for checking whether two ApkAssets are the same.
-  //  With the introduction of ResourcesProviders, not all ApkAssets have paths. This could cause
-  //  bugs when path is used for comparison because multiple ApkAssets could have the same "firendly
-  //  name". Use pointer equality instead. ResourceManager caches and reuses ApkAssets so the
-  //  same asset should have the same pointer.
-  const std::string& GetPath() const;
+  // Path to the contents of the ApkAssets on disk. The path could represent an APk, a directory,
+  // or some other file type.
+  std::optional<std::string_view> GetPath() const;
+
+  const std::string& GetDebugName() const;
 
   const AssetsProvider* GetAssetsProvider() const {
     return assets_provider_.get();
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index 2255973f..119f531 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -412,7 +412,7 @@
   void RebuildFilterList();
 
   // Retrieves the APK paths of overlays that overlay non-system packages.
-  std::set<std::string> GetNonSystemOverlayPaths() const;
+  std::set<const ApkAssets*> GetNonSystemOverlays() const;
 
   // AssetManager2::GetBag(resid) wraps this function to track which resource ids have already
   // been seen while traversing bag parents.
diff --git a/libs/androidfw/include/androidfw/AssetsProvider.h b/libs/androidfw/include/androidfw/AssetsProvider.h
index 6f16ff4..63bbdcc 100644
--- a/libs/androidfw/include/androidfw/AssetsProvider.h
+++ b/libs/androidfw/include/androidfw/AssetsProvider.h
@@ -48,6 +48,10 @@
   virtual bool ForEachFile(const std::string& path,
                            const std::function<void(const StringPiece&, FileType)>& f) const = 0;
 
+  // Retrieves the path to the contents of the AssetsProvider on disk. The path could represent an
+  // APk, a directory, or some other file type.
+  WARN_UNUSED virtual std::optional<std::string_view> GetPath() const = 0;
+
   // Retrieves a name that represents the interface. This may or may not be the path of the
   // interface source.
   WARN_UNUSED virtual const std::string& GetDebugName() const = 0;
@@ -85,9 +89,9 @@
   bool ForEachFile(const std::string& root_path,
                    const std::function<void(const StringPiece&, FileType)>& f) const override;
 
+  WARN_UNUSED std::optional<std::string_view> GetPath() const override;
   WARN_UNUSED const std::string& GetDebugName() const override;
   WARN_UNUSED bool IsUpToDate() const override;
-
   WARN_UNUSED std::optional<uint32_t> GetCrc(std::string_view path) const;
 
   ~ZipAssetsProvider() override = default;
@@ -125,6 +129,7 @@
   bool ForEachFile(const std::string& path,
                    const std::function<void(const StringPiece&, FileType)>& f) const override;
 
+  WARN_UNUSED std::optional<std::string_view> GetPath() const override;
   WARN_UNUSED const std::string& GetDebugName() const override;
   WARN_UNUSED bool IsUpToDate() const override;
 
@@ -149,6 +154,7 @@
   bool ForEachFile(const std::string& root_path,
                    const std::function<void(const StringPiece&, FileType)>& f) const override;
 
+  WARN_UNUSED std::optional<std::string_view> GetPath() const override;
   WARN_UNUSED const std::string& GetDebugName() const override;
   WARN_UNUSED bool IsUpToDate() const override;
 
@@ -163,6 +169,7 @@
 
   std::unique_ptr<AssetsProvider> primary_;
   std::unique_ptr<AssetsProvider> secondary_;
+  std::optional<std::string_view> path_;
   std::string debug_name_;
 };
 
@@ -173,6 +180,7 @@
   bool ForEachFile(const std::string& path,
                   const std::function<void(const StringPiece&, FileType)>& f) const override;
 
+  WARN_UNUSED std::optional<std::string_view> GetPath() const override;
   WARN_UNUSED const std::string& GetDebugName() const override;
   WARN_UNUSED bool IsUpToDate() const override;
 
diff --git a/libs/hwui/FrameInfo.cpp b/libs/hwui/FrameInfo.cpp
index 5d3f6f2..2448cc9 100644
--- a/libs/hwui/FrameInfo.cpp
+++ b/libs/hwui/FrameInfo.cpp
@@ -20,13 +20,12 @@
 namespace android {
 namespace uirenderer {
 
-const std::array<std::string, static_cast<int>(FrameInfoIndex::NumIndexes)> FrameInfoNames = {
+const std::array FrameInfoNames{
         "Flags",
         "FrameTimelineVsyncId",
         "IntendedVsync",
         "Vsync",
-        "OldestInputEvent",
-        "NewestInputEvent",
+        "InputEventId",
         "HandleInputStart",
         "AnimationStart",
         "PerformTraversalsStart",
@@ -40,7 +39,8 @@
         "DequeueBufferDuration",
         "QueueBufferDuration",
         "GpuCompleted",
-        "SwapBuffersCompleted"
+        "SwapBuffersCompleted",
+        "DisplayPresentTime",
 };
 
 static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 20,
diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h
index 45a367f..912d04c5 100644
--- a/libs/hwui/FrameInfo.h
+++ b/libs/hwui/FrameInfo.h
@@ -28,15 +28,14 @@
 namespace android {
 namespace uirenderer {
 
-#define UI_THREAD_FRAME_INFO_SIZE 11
+static constexpr size_t UI_THREAD_FRAME_INFO_SIZE = 10;
 
 enum class FrameInfoIndex {
     Flags = 0,
     FrameTimelineVsyncId,
     IntendedVsync,
     Vsync,
-    OldestInputEvent,
-    NewestInputEvent,
+    InputEventId,
     HandleInputStart,
     AnimationStart,
     PerformTraversalsStart,
@@ -56,13 +55,14 @@
 
     GpuCompleted,
     SwapBuffersCompleted,
+    DisplayPresentTime,
 
     // Must be the last value!
     // Also must be kept in sync with FrameMetrics.java#FRAME_STATS_COUNT
     NumIndexes
 };
 
-extern const std::array<std::string, static_cast<int>(FrameInfoIndex::NumIndexes)> FrameInfoNames;
+extern const std::array<const char*, static_cast<int>(FrameInfoIndex::NumIndexes)> FrameInfoNames;
 
 namespace FrameInfoFlags {
 enum {
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index b570af5..4eefe92 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -219,7 +219,7 @@
 void JankTracker::dumpFrames(int fd) {
     dprintf(fd, "\n\n---PROFILEDATA---\n");
     for (size_t i = 0; i < static_cast<size_t>(FrameInfoIndex::NumIndexes); i++) {
-        dprintf(fd, "%s", FrameInfoNames[i].c_str());
+        dprintf(fd, "%s", FrameInfoNames[i]);
         dprintf(fd, ",");
     }
     for (size_t i = 0; i < mFrames.size(); i++) {
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index df66981..f24ba5c 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -240,8 +240,8 @@
 static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize) {
     LOG_ALWAYS_FATAL_IF(frameInfoSize != UI_THREAD_FRAME_INFO_SIZE,
-            "Mismatched size expectations, given %d expected %d",
-            frameInfoSize, UI_THREAD_FRAME_INFO_SIZE);
+                        "Mismatched size expectations, given %d expected %zu", frameInfoSize,
+                        UI_THREAD_FRAME_INFO_SIZE);
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     env->GetLongArrayRegion(frameInfo, 0, frameInfoSize, proxy->frameInfo());
     return proxy->syncAndDrawFrame();
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 389fe7e..50eea31 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -105,7 +105,6 @@
     LightingInfo::updateLighting(lightGeometry, lightInfo);
     renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface,
                 SkMatrix::I());
-    layerUpdateQueue->clear();
 
     // Draw visual debugging features
     if (CC_UNLIKELY(Properties::showDirtyRegions ||
@@ -113,9 +112,14 @@
         SkCanvas* profileCanvas = surface->getCanvas();
         SkiaProfileRenderer profileRenderer(profileCanvas);
         profiler->draw(profileRenderer);
-        profileCanvas->flush();
     }
 
+    {
+        ATRACE_NAME("flush commands");
+        surface->flushAndSubmit();
+    }
+    layerUpdateQueue->clear();
+
     // Log memory statistics
     if (CC_UNLIKELY(Properties::debugLevel != kDebugDisabled)) {
         dumpResourceCacheUsage();
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 6456e36..1f73ac9 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -454,9 +454,6 @@
         renderOverdraw(clip, nodes, contentDrawBounds, surface, preTransform);
     }
 
-    ATRACE_NAME("flush commands");
-    surface->flushAndSubmit();
-
     Properties::skpCaptureEnabled = previousSkpEnabled;
 }
 
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index af7271e..61f9960 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -176,9 +176,6 @@
     if (sApiLevel <= 27 && paint.getBlendMode() == SkBlendMode::kClear) {
         paint.setBlendMode(SkBlendMode::kDstOut);
     }
-
-    // disabling AA on bitmap draws matches legacy HWUI behavior
-    paint.setAntiAlias(false);
 }
 
 static SkFilterMode Paint_to_filter(const SkPaint& paint) {
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index ad6363b..1bd943f 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -17,14 +17,15 @@
 #include "SkiaVulkanPipeline.h"
 
 #include "DeferredLayerUpdater.h"
+#include "LightingInfo.h"
 #include "Readback.h"
 #include "ShaderCache.h"
-#include "LightingInfo.h"
 #include "SkiaPipeline.h"
 #include "SkiaProfileRenderer.h"
 #include "VkInteropFunctorDrawable.h"
 #include "renderstate/RenderState.h"
 #include "renderthread/Frame.h"
+#include "utils/TraceUtils.h"
 
 #include <SkSurface.h>
 #include <SkTypes.h>
@@ -73,8 +74,6 @@
     LightingInfo::updateLighting(lightGeometry, lightInfo);
     renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, backBuffer,
                 mVkSurface->getCurrentPreTransform());
-    ShaderCache::get().onVkFrameFlushed(mRenderThread.getGrContext());
-    layerUpdateQueue->clear();
 
     // Draw visual debugging features
     if (CC_UNLIKELY(Properties::showDirtyRegions ||
@@ -82,9 +81,14 @@
         SkCanvas* profileCanvas = backBuffer->getCanvas();
         SkiaProfileRenderer profileRenderer(profileCanvas);
         profiler->draw(profileRenderer);
-        profileCanvas->flush();
     }
 
+    {
+        ATRACE_NAME("flush commands");
+        mVkManager.finishFrame(backBuffer.get());
+    }
+    layerUpdateQueue->clear();
+
     // Log memory statistics
     if (CC_UNLIKELY(Properties::debugLevel != kDebugDisabled)) {
         dumpResourceCacheUsage();
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index b760db2..f69ddac 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -484,7 +484,8 @@
         // TODO(b/165985262): measure performance impact
         const auto vsyncId = mCurrentFrameInfo->get(FrameInfoIndex::FrameTimelineVsyncId);
         if (vsyncId != UiFrameInfoBuilder::INVALID_VSYNC_ID) {
-            const auto inputEventId = mCurrentFrameInfo->get(FrameInfoIndex::NewestInputEvent);
+            const auto inputEventId =
+                    static_cast<int32_t>(mCurrentFrameInfo->get(FrameInfoIndex::InputEventId));
             native_window_set_frame_timeline_info(mNativeSurface->getNativeWindow(), vsyncId,
                                                   inputEventId);
         }
@@ -591,7 +592,6 @@
 }
 
 void CanvasContext::finishFrame(FrameInfo* frameInfo) {
-
     // TODO (b/169858044): Consolidate this into a single call.
     mJankTracker.finishFrame(*frameInfo);
     mJankTracker.finishGpuDraw(*frameInfo);
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 3e7ce36..e93824d 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -31,6 +31,7 @@
 
 #include "Properties.h"
 #include "RenderThread.h"
+#include "pipeline/skia/ShaderCache.h"
 #include "renderstate/RenderState.h"
 #include "utils/TraceUtils.h"
 
@@ -476,17 +477,10 @@
     }
 }
 
-void VulkanManager::swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect) {
-    if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
-        ATRACE_NAME("Finishing GPU work");
-        mDeviceWaitIdle(mDevice);
-    }
-
-    VulkanSurface::NativeBufferInfo* bufferInfo = surface->getCurrentBufferInfo();
-    if (!bufferInfo) {
-        // If VulkanSurface::dequeueNativeBuffer failed earlier, then swapBuffers is a no-op.
-        return;
-    }
+void VulkanManager::finishFrame(SkSurface* surface) {
+    ATRACE_NAME("Vulkan finish frame");
+    ALOGE_IF(mSwapSemaphore != VK_NULL_HANDLE || mDestroySemaphoreContext != nullptr,
+             "finishFrame already has an outstanding semaphore");
 
     VkExportSemaphoreCreateInfo exportInfo;
     exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
@@ -499,32 +493,52 @@
     semaphoreInfo.flags = 0;
     VkSemaphore semaphore;
     VkResult err = mCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &semaphore);
-    ALOGE_IF(VK_SUCCESS != err, "VulkanManager::swapBuffers(): Failed to create semaphore");
+    ALOGE_IF(VK_SUCCESS != err, "VulkanManager::makeSwapSemaphore(): Failed to create semaphore");
 
     GrBackendSemaphore backendSemaphore;
     backendSemaphore.initVulkan(semaphore);
 
-    int fenceFd = -1;
-    DestroySemaphoreInfo* destroyInfo =
-            new DestroySemaphoreInfo(mDestroySemaphore, mDevice, semaphore);
     GrFlushInfo flushInfo;
-    flushInfo.fNumSemaphores = 1;
-    flushInfo.fSignalSemaphores = &backendSemaphore;
-    flushInfo.fFinishedProc = destroy_semaphore;
-    flushInfo.fFinishedContext = destroyInfo;
-    GrSemaphoresSubmitted submitted = bufferInfo->skSurface->flush(
-            SkSurface::BackendSurfaceAccess::kPresent, flushInfo);
-    GrDirectContext* context = GrAsDirectContext(bufferInfo->skSurface->recordingContext());
+    if (err == VK_SUCCESS) {
+        mDestroySemaphoreContext = new DestroySemaphoreInfo(mDestroySemaphore, mDevice, semaphore);
+        flushInfo.fNumSemaphores = 1;
+        flushInfo.fSignalSemaphores = &backendSemaphore;
+        flushInfo.fFinishedProc = destroy_semaphore;
+        flushInfo.fFinishedContext = mDestroySemaphoreContext;
+    } else {
+        semaphore = VK_NULL_HANDLE;
+    }
+    GrSemaphoresSubmitted submitted =
+            surface->flush(SkSurface::BackendSurfaceAccess::kPresent, flushInfo);
+    GrDirectContext* context = GrAsDirectContext(surface->recordingContext());
     ALOGE_IF(!context, "Surface is not backed by gpu");
     context->submit();
-    if (submitted == GrSemaphoresSubmitted::kYes) {
+    if (semaphore != VK_NULL_HANDLE) {
+        if (submitted == GrSemaphoresSubmitted::kYes) {
+            mSwapSemaphore = semaphore;
+        } else {
+            destroy_semaphore(mDestroySemaphoreContext);
+            mDestroySemaphoreContext = nullptr;
+        }
+    }
+    skiapipeline::ShaderCache::get().onVkFrameFlushed(context);
+}
+
+void VulkanManager::swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect) {
+    if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
+        ATRACE_NAME("Finishing GPU work");
+        mDeviceWaitIdle(mDevice);
+    }
+
+    int fenceFd = -1;
+    if (mSwapSemaphore != VK_NULL_HANDLE) {
         VkSemaphoreGetFdInfoKHR getFdInfo;
         getFdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR;
         getFdInfo.pNext = nullptr;
-        getFdInfo.semaphore = semaphore;
+        getFdInfo.semaphore = mSwapSemaphore;
         getFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
 
-        err = mGetSemaphoreFdKHR(mDevice, &getFdInfo, &fenceFd);
+        VkResult err = mGetSemaphoreFdKHR(mDevice, &getFdInfo, &fenceFd);
         ALOGE_IF(VK_SUCCESS != err, "VulkanManager::swapBuffers(): Failed to get semaphore Fd");
     } else {
         ALOGE("VulkanManager::swapBuffers(): Semaphore submission failed");
@@ -532,9 +546,11 @@
         std::lock_guard<std::mutex> lock(mGraphicsQueueMutex);
         mQueueWaitIdle(mGraphicsQueue);
     }
-    destroy_semaphore(destroyInfo);
+    destroy_semaphore(mDestroySemaphoreContext);
 
     surface->presentCurrentBuffer(dirtyRect, fenceFd);
+    mSwapSemaphore = VK_NULL_HANDLE;
+    mDestroySemaphoreContext = nullptr;
 }
 
 void VulkanManager::destroySurface(VulkanSurface* surface) {
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 121afc9..0912369 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -69,6 +69,7 @@
     void destroySurface(VulkanSurface* surface);
 
     Frame dequeueNextBuffer(VulkanSurface* surface);
+    void finishFrame(SkSurface* surface);
     void swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect);
 
     // Inserts a wait on fence command into the Vulkan command buffer.
@@ -200,6 +201,9 @@
     SwapBehavior mSwapBehavior = SwapBehavior::Discard;
     GrVkExtensions mExtensions;
     uint32_t mDriverVersion = 0;
+
+    VkSemaphore mSwapSemaphore = VK_NULL_HANDLE;
+    void* mDestroySemaphoreContext = nullptr;
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/tests/unit/TypefaceTests.cpp b/libs/hwui/tests/unit/TypefaceTests.cpp
index ab23448..1a3dbe7 100644
--- a/libs/hwui/tests/unit/TypefaceTests.cpp
+++ b/libs/hwui/tests/unit/TypefaceTests.cpp
@@ -33,7 +33,7 @@
 
 constexpr char kRobotoVariable[] = "/system/fonts/Roboto-Regular.ttf";
 
-constexpr char kRegularFont[] = "/system/fonts/NotoSerif-Regular.ttf";
+constexpr char kRegularFont[] = "/system/fonts/NotoSerif.ttf";
 constexpr char kBoldFont[] = "/system/fonts/NotoSerif-Bold.ttf";
 constexpr char kItalicFont[] = "/system/fonts/NotoSerif-Italic.ttf";
 constexpr char kBoldItalicFont[] = "/system/fonts/NotoSerif-BoldItalic.ttf";
diff --git a/location/java/android/location/GnssAntennaInfo.java b/location/java/android/location/GnssAntennaInfo.java
index f1eb8fc..6633d24 100644
--- a/location/java/android/location/GnssAntennaInfo.java
+++ b/location/java/android/location/GnssAntennaInfo.java
@@ -39,11 +39,7 @@
 
     /**
      * Used for receiving GNSS antenna info from the GNSS engine.
-     *
-     * @deprecated Prefer to use a broadcast receiver for
-     * {@link LocationManager#ACTION_GNSS_ANTENNA_INFOS_CHANGED}.
      */
-    @Deprecated
     public interface Listener {
         /**
          * Invoked on a change to GNSS antenna info.
diff --git a/location/java/android/location/IGnssAntennaInfoListener.aidl b/location/java/android/location/IGnssAntennaInfoListener.aidl
new file mode 100644
index 0000000..3cceea3
--- /dev/null
+++ b/location/java/android/location/IGnssAntennaInfoListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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 android.location;
+
+import android.location.GnssAntennaInfo;
+
+/**
+ * {@hide}
+ */
+oneway interface IGnssAntennaInfoListener {
+    void onGnssAntennaInfoChanged(in List<GnssAntennaInfo> antennaInfos);
+}
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 5e39660..6fa6536 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -26,6 +26,7 @@
 import android.location.GnssMeasurementCorrections;
 import android.location.GnssMeasurementRequest;
 import android.location.IGeocodeListener;
+import android.location.IGnssAntennaInfoListener;
 import android.location.IGnssMeasurementsListener;
 import android.location.IGnssStatusListener;
 import android.location.IGnssNavigationMessageListener;
@@ -92,6 +93,9 @@
     void addGnssNavigationMessageListener(in IGnssNavigationMessageListener listener, String packageName, @nullable String attributionTag, String listenerId);
     void removeGnssNavigationMessageListener(in IGnssNavigationMessageListener listener);
 
+    void addGnssAntennaInfoListener(in IGnssAntennaInfoListener listener, String packageName, @nullable String attributionTag, String listenerId);
+    void removeGnssAntennaInfoListener(in IGnssAntennaInfoListener listener);
+
     void addProviderRequestListener(in IProviderRequestListener listener);
     void removeProviderRequestListener(in IProviderRequestListener listener);
 
@@ -117,7 +121,8 @@
     boolean isLocationEnabledForUser(int userId);
     void setLocationEnabledForUser(boolean enabled, int userId);
 
-    void addTestProvider(String name, in ProviderProperties properties, String packageName, @nullable String attributionTag);
+    void addTestProvider(String name, in ProviderProperties properties,
+        in List<String> locationTags, String packageName, @nullable String attributionTag);
     void removeTestProvider(String provider, String packageName, @nullable String attributionTag);
     void setTestProviderLocation(String provider, in Location location, String packageName, @nullable String attributionTag);
     void setTestProviderEnabled(String provider, boolean enabled, String packageName, @nullable String attributionTag);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index dd5b6e6..e73e915 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -43,10 +43,8 @@
 import android.compat.Compatibility;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledAfter;
-import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.location.provider.IProviderRequestListener;
 import android.location.provider.ProviderProperties;
@@ -76,6 +74,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 import java.util.WeakHashMap;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
@@ -348,28 +347,6 @@
     public static final String EXTRA_GNSS_CAPABILITIES = "android.location.extra.GNSS_CAPABILITIES";
 
     /**
-     * Broadcast intent action when GNSS antenna infos change. Includes an intent extra,
-     * {@link #EXTRA_GNSS_ANTENNA_INFOS}, with an ArrayList of the new {@link GnssAntennaInfo}. This
-     * may be read via {@link android.content.Intent#getParcelableArrayListExtra(String)}.
-     *
-     * @see #EXTRA_GNSS_ANTENNA_INFOS
-     * @see #getGnssAntennaInfos()
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_GNSS_ANTENNA_INFOS_CHANGED =
-            "android.location.action.GNSS_ANTENNA_INFOS_CHANGED";
-
-    /**
-     * Intent extra included with {@link #ACTION_GNSS_ANTENNA_INFOS_CHANGED} broadcasts, containing
-     * the new ArrayList of {@link GnssAntennaInfo}. This may be read via
-     * {@link android.content.Intent#getParcelableArrayListExtra(String)}.
-     *
-     * @see #ACTION_GNSS_ANTENNA_INFOS_CHANGED
-     */
-    public static final String EXTRA_GNSS_ANTENNA_INFOS =
-            "android.location.extra.GNSS_ANTENNA_INFOS";
-
-    /**
      * Broadcast intent action for Settings app to inject a footer at the bottom of location
      * settings. This is for use only by apps that are included in the system image.
      *
@@ -1957,12 +1934,33 @@
      * allowed} for your app.
      */
     public void addTestProvider(@NonNull String provider, @NonNull ProviderProperties properties) {
+        addTestProvider(provider, properties, Collections.emptySet());
+    }
+
+    /**
+     * Creates a test location provider and adds it to the set of active providers. This provider
+     * will replace any provider with the same name that exists prior to this call.
+     *
+     * @param provider the provider name
+     * @param properties the provider properties
+     * @param extraAttributionTags additional attribution tags associated with this provider
+     *
+     * @throws IllegalArgumentException if provider is null
+     * @throws IllegalArgumentException if properties is null
+     * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
+     * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
+     * allowed} for your app.
+     */
+    public void addTestProvider(@NonNull String provider, @NonNull ProviderProperties properties,
+            @NonNull Set<String> extraAttributionTags) {
         Preconditions.checkArgument(provider != null, "invalid null provider");
         Preconditions.checkArgument(properties != null, "invalid null properties");
+        Preconditions.checkArgument(extraAttributionTags != null,
+                "invalid null extra attribution tags");
 
         try {
-            mService.addTestProvider(provider, properties, mContext.getOpPackageName(),
-                    mContext.getFeatureId());
+            mService.addTestProvider(provider, properties, new ArrayList<>(extraAttributionTags),
+                    mContext.getOpPackageName(), mContext.getFeatureId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2638,10 +2636,11 @@
     }
 
     /**
-     * Registers a GNSS antenna info listener. GNSS antenna info updates will only be received while
-     * the {@link #GPS_PROVIDER} is enabled, and while the client app is in the foreground.
+     * Registers a GNSS antenna info listener that will receive all changes to antenna info. Use
+     * {@link #getGnssAntennaInfos()} to get current antenna info.
      *
-     * <p>Not all GNSS chipsets support antenna info updates, see {@link #getGnssCapabilities()}.
+     * <p>Not all GNSS chipsets support antenna info updates, see {@link #getGnssCapabilities()}. If
+     * unsupported, the listener will never be invoked.
      *
      * <p>Prior to Android S, this requires the {@link Manifest.permission#ACCESS_FINE_LOCATION}
      * permission.
@@ -2652,10 +2651,7 @@
      *
      * @throws IllegalArgumentException if executor is null
      * @throws IllegalArgumentException if listener is null
-     *
-     * @deprecated Prefer to use a receiver for {@link #ACTION_GNSS_ANTENNA_INFOS_CHANGED}.
      */
-    @Deprecated
     public boolean registerAntennaInfoListener(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull GnssAntennaInfo.Listener listener) {
@@ -2665,13 +2661,10 @@
     }
 
     /**
-     * Unregisters a GNSS Antenna Info listener.
+     * Unregisters a GNSS antenna info listener.
      *
      * @param listener a {@link GnssAntennaInfo.Listener} object to remove
-     *
-     * @deprecated Prefer to use a receiver for {@link #ACTION_GNSS_ANTENNA_INFOS_CHANGED}.
      */
-    @Deprecated
     public void unregisterAntennaInfoListener(@NonNull GnssAntennaInfo.Listener listener) {
         GnssLazyLoader.sGnssAntennaInfoListeners.removeListener(listener);
     }
@@ -2988,14 +2981,17 @@
         }
 
         @Override
-        protected void registerTransport(GnssAntennaInfoTransport transport) {
-            transport.getContext().registerReceiver(transport,
-                    new IntentFilter(ACTION_GNSS_ANTENNA_INFOS_CHANGED));
+        protected void registerTransport(GnssAntennaInfoTransport transport)
+                throws RemoteException {
+            getService().addGnssAntennaInfoListener(transport, transport.getPackage(),
+                    transport.getAttributionTag(),
+                    AppOpsManager.toReceiverId(transport.getListener()));
         }
 
         @Override
-        protected void unregisterTransport(GnssAntennaInfoTransport transport) {
-            transport.getContext().unregisterReceiver(transport);
+        protected void unregisterTransport(GnssAntennaInfoTransport transport)
+                throws RemoteException {
+            getService().removeGnssAntennaInfoListener(transport);
         }
     }
 
@@ -3355,11 +3351,12 @@
         }
     }
 
-    private static class GnssAntennaInfoTransport extends BroadcastReceiver implements
+    private static class GnssAntennaInfoTransport extends IGnssAntennaInfoListener.Stub implements
             ListenerTransport<GnssAntennaInfo.Listener> {
 
         private final Executor mExecutor;
-        private final Context mContext;
+        private final String mPackageName;
+        private final String mAttributionTag;
 
         private volatile @Nullable GnssAntennaInfo.Listener mListener;
 
@@ -3368,12 +3365,17 @@
             Preconditions.checkArgument(executor != null, "invalid null executor");
             Preconditions.checkArgument(listener != null, "invalid null listener");
             mExecutor = executor;
-            mContext = context;
+            mPackageName = context.getPackageName();
+            mAttributionTag = context.getAttributionTag();
             mListener = listener;
         }
 
-        public Context getContext() {
-            return mContext;
+        public String getPackage() {
+            return mPackageName;
+        }
+
+        public String getAttributionTag() {
+            return mAttributionTag;
         }
 
         @Override
@@ -3387,12 +3389,8 @@
         }
 
         @Override
-        public void onReceive(Context context, Intent intent) {
-            ArrayList<GnssAntennaInfo> infos = intent.getParcelableArrayListExtra(
-                    EXTRA_GNSS_ANTENNA_INFOS);
-            if (infos != null) {
-                execute(mExecutor, callback -> callback.onGnssAntennaInfoReceived(infos));
-            }
+        public void onGnssAntennaInfoChanged(List<GnssAntennaInfo> antennaInfos) {
+            execute(mExecutor, callback -> callback.onGnssAntennaInfoReceived(antennaInfos));
         }
     }
 
diff --git a/location/java/android/location/LocationManagerInternal.java b/location/java/android/location/LocationManagerInternal.java
index a6a0e7a..763835c 100644
--- a/location/java/android/location/LocationManagerInternal.java
+++ b/location/java/android/location/LocationManagerInternal.java
@@ -21,6 +21,10 @@
 import android.annotation.Nullable;
 import android.location.util.identity.CallerIdentity;
 
+import com.android.internal.annotations.Immutable;
+
+import java.util.Set;
+
 /**
  * Location manager local system service interface.
  *
@@ -39,6 +43,21 @@
     }
 
     /**
+     * Interface for getting callbacks when a location provider's location tags change.
+     *
+     * @see LocationTagInfo
+     */
+    public interface OnProviderLocationTagsChangeListener {
+
+        /**
+         * Called when the location tags for a provider change.
+         *
+         * @param providerLocationTagInfo The tag info for a provider.
+         */
+        void onLocationTagsChanged(@NonNull LocationTagInfo providerLocationTagInfo);
+    }
+
+    /**
      * Returns true if the given provider is enabled for the given user.
      *
      * @param provider A location provider as listed by {@link LocationManager#getAllProviders()}
@@ -88,4 +107,60 @@
      * provider, and the elapsed nanos since boot the current time was computed at.
      */
     public abstract @Nullable LocationTime getGnssTimeMillis();
+
+    /**
+     * Sets a listener for changes in the location providers' tags. Passing
+     * {@code null} clears the current listener.
+     *
+     * @param listener The listener.
+     */
+    public abstract void setOnProviderLocationTagsChangeListener(
+            @Nullable OnProviderLocationTagsChangeListener listener);
+
+    /**
+     * This class represents the location permission tags used by the location provider
+     * packages in a given UID. These tags are strictly used for accessing state guarded
+     * by the location permission(s) by a location provider which are required for the
+     * provider to fulfill its function as being a location provider.
+     */
+    @Immutable
+    public static class LocationTagInfo {
+        private final int mUid;
+
+        @NonNull
+        private final String mPackageName;
+
+        @Nullable
+        private final Set<String> mLocationTags;
+
+        public LocationTagInfo(int uid, @NonNull String packageName,
+                @Nullable Set<String> locationTags) {
+            mUid = uid;
+            mPackageName = packageName;
+            mLocationTags = locationTags;
+        }
+
+        /**
+         * @return The UID for which tags are related.
+         */
+        public int getUid() {
+            return mUid;
+        }
+
+        /**
+         * @return The package for which tags are related.
+         */
+        @NonNull
+        public String getPackageName() {
+            return mPackageName;
+        }
+
+        /**
+         * @return The tags for the package used for location related accesses.
+         */
+        @Nullable
+        public Set<String> getTags() {
+            return mLocationTags;
+        }
+    }
 }
diff --git a/location/java/android/location/util/identity/CallerIdentity.java b/location/java/android/location/util/identity/CallerIdentity.java
index 0bb7dbb..85a083e 100644
--- a/location/java/android/location/util/identity/CallerIdentity.java
+++ b/location/java/android/location/util/identity/CallerIdentity.java
@@ -42,7 +42,16 @@
     @VisibleForTesting
     public static CallerIdentity forTest(int uid, int pid, String packageName,
             @Nullable String attributionTag) {
-        return new CallerIdentity(uid, pid, packageName, attributionTag, null);
+        return forTest(uid, pid, packageName, attributionTag, null);
+    }
+
+    /**
+     * Construct a CallerIdentity for test purposes.
+     */
+    @VisibleForTesting
+    public static CallerIdentity forTest(int uid, int pid, String packageName,
+            @Nullable String attributionTag, @Nullable String listenerId) {
+        return new CallerIdentity(uid, pid, packageName, attributionTag, listenerId);
     }
 
     /**
@@ -145,7 +154,10 @@
         return mAttributionTag;
     }
 
-    /** The calling listener id. */
+    /**
+     * The calling listener id. A null listener id will match any other listener id for the purposes
+     * of {@link #equals(Object)}.
+     */
     public String getListenerId() {
         return mListenerId;
     }
@@ -168,6 +180,17 @@
         }
     }
 
+    /**
+     * Returns a CallerIdentity corrosponding to this CallerIdentity but with a null listener id.
+     */
+    public CallerIdentity stripListenerId() {
+        if (mListenerId == null) {
+            return this;
+        } else {
+            return new CallerIdentity(mUid, mPid, mPackageName, mAttributionTag, null);
+        }
+    }
+
     @Override
     public String toString() {
         int length = 10 + mPackageName.length();
@@ -201,15 +224,12 @@
             return false;
         }
         CallerIdentity that = (CallerIdentity) o;
-        return equalsIgnoringListenerId(that) && Objects.equals(mListenerId, that.mListenerId);
-    }
-
-    public boolean equalsIgnoringListenerId(CallerIdentity that) {
-        return that != null
-                && mUid == that.mUid
+        return mUid == that.mUid
                 && mPid == that.mPid
                 && mPackageName.equals(that.mPackageName)
-                && Objects.equals(mAttributionTag, that.mAttributionTag);
+                && Objects.equals(mAttributionTag, that.mAttributionTag)
+                && (mListenerId == null || that.mListenerId == null || mListenerId.equals(
+                that.mListenerId));
     }
 
     @Override
diff --git a/media/aidl/android/media/soundtrigger_middleware/SoundModel.aidl b/media/aidl/android/media/soundtrigger_middleware/SoundModel.aidl
index cee3635..8186fb7 100644
--- a/media/aidl/android/media/soundtrigger_middleware/SoundModel.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/SoundModel.aidl
@@ -32,8 +32,8 @@
      * Unique vendor ID. Identifies the engine the sound model
      * was build for */
     String vendorUuid;
-    /** Opaque data transparent to Android framework */
-    ParcelFileDescriptor data;
+    /** Opaque data transparent to Android framework. May be null if dataSize is 0. */
+    @nullable ParcelFileDescriptor data;
     /** Size of the above data, in bytes. */
     int dataSize;
 }
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index bb1dbd4..7e729d8 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -1264,6 +1264,8 @@
      *
      * @param usage one of the {@link AudioAttributes} usage constants
      * @return string representing the {@link AudioAttributes} usage constant passed as a parameter
+     *
+     * @hide
      */
     @NonNull
     public static String usageToString(@AttributeSdkUsage int usage) {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index f87f90d..b2de49d 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -568,7 +568,7 @@
     public static final int FLAG_FROM_KEY = 1 << 12;
 
     /** @hide */
-    @IntDef(flag = false, prefix = "FLAG", value = {
+    @IntDef(flag = true, prefix = "FLAG", value = {
             FLAG_SHOW_UI,
             FLAG_ALLOW_RINGER_MODES,
             FLAG_PLAY_SOUND,
diff --git a/media/java/android/media/AudioMetadata.java b/media/java/android/media/AudioMetadata.java
index ff9fd41..ca175b4 100644
--- a/media/java/android/media/AudioMetadata.java
+++ b/media/java/android/media/AudioMetadata.java
@@ -195,6 +195,61 @@
         @NonNull public static final Key<Integer> KEY_AUDIO_ENCODING =
                 createKey("audio-encoding", Integer.class);
 
+
+        /**
+         * A key representing the audio presentation id being decoded by a next generation
+         * audio decoder.
+         *
+         * An Integer value representing presentation id.
+         *
+         * @see AudioPresentation#getPresentationId()
+         */
+        @NonNull public static final Key<Integer> KEY_PRESENTATION_ID =
+                createKey("presentation-id", Integer.class);
+
+         /**
+         * A key representing the audio program id being decoded by a next generation
+         * audio decoder.
+         *
+         * An Integer value representing program id.
+         *
+         * @see AudioPresentation#getProgramId()
+         */
+        @NonNull public static final Key<Integer> KEY_PROGRAM_ID =
+                createKey("program-id", Integer.class);
+
+
+         /**
+         * A key representing the audio presentation content classifier being rendered
+         * by a next generation audio decoder.
+         *
+         * An Integer value representing presentation content classifier.
+         *
+         * @see AudioPresentation.ContentClassifier
+         * One of {@link AudioPresentation#CONTENT_UNKNOWN},
+         *     {@link AudioPresentation#CONTENT_MAIN},
+         *     {@link AudioPresentation#CONTENT_MUSIC_AND_EFFECTS},
+         *     {@link AudioPresentation#CONTENT_VISUALLY_IMPAIRED},
+         *     {@link AudioPresentation#CONTENT_HEARING_IMPAIRED},
+         *     {@link AudioPresentation#CONTENT_DIALOG},
+         *     {@link AudioPresentation#CONTENT_COMMENTARY},
+         *     {@link AudioPresentation#CONTENT_EMERGENCY},
+         *     {@link AudioPresentation#CONTENT_VOICEOVER}.
+         */
+        @NonNull public static final Key<Integer> KEY_PRESENTATION_CONTENT_CLASSIFIER =
+                createKey("presentation-content-classifier", Integer.class);
+
+        /**
+         * A key representing the audio presentation language being rendered by a next
+         * generation audio decoder.
+         *
+         * A String value representing ISO 639-2 (three letter code).
+         *
+         * @see AudioPresentation#getLocale()
+         */
+        @NonNull public static final Key<String> KEY_PRESENTATION_LANGUAGE =
+                createKey("presentation-language", String.class);
+
         private Format() {} // delete constructor
     }
 
diff --git a/media/java/android/media/AudioPresentation.java b/media/java/android/media/AudioPresentation.java
index 894fbba..47358be 100644
--- a/media/java/android/media/AudioPresentation.java
+++ b/media/java/android/media/AudioPresentation.java
@@ -57,6 +57,64 @@
     /** @hide */
     @IntDef(
         value = {
+        CONTENT_UNKNOWN,
+        CONTENT_MAIN,
+        CONTENT_MUSIC_AND_EFFECTS,
+        CONTENT_VISUALLY_IMPAIRED,
+        CONTENT_HEARING_IMPAIRED,
+        CONTENT_DIALOG,
+        CONTENT_COMMENTARY,
+        CONTENT_EMERGENCY,
+        CONTENT_VOICEOVER,
+    })
+
+    /**
+     * The ContentClassifier int definitions represent the AudioPresentation content
+     * classifier (as per TS 103 190-1 v1.2.1 4.3.3.8.1)
+    */
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ContentClassifier {}
+
+    /**
+     * Audio presentation classifier: Unknown.
+     */
+    public static final int CONTENT_UNKNOWN                 = -1;
+    /**
+     * Audio presentation classifier: Complete main.
+     */
+    public static final int CONTENT_MAIN                    = 0;
+    /**
+     * Audio presentation content classifier: Music and effects.
+     */
+    public static final int CONTENT_MUSIC_AND_EFFECTS       = 1;
+    /**
+     * Audio presentation content classifier: Visually impaired.
+     */
+    public static final int CONTENT_VISUALLY_IMPAIRED       = 2;
+    /**
+     * Audio presentation content classifier: Hearing impaired.
+     */
+    public static final int CONTENT_HEARING_IMPAIRED        = 3;
+    /**
+     * Audio presentation content classifier: Dialog.
+     */
+    public static final int CONTENT_DIALOG                  = 4;
+    /**
+     * Audio presentation content classifier: Commentary.
+     */
+    public static final int CONTENT_COMMENTARY              = 5;
+    /**
+     * Audio presentation content classifier: Emergency.
+     */
+    public static final int CONTENT_EMERGENCY               = 6;
+    /**
+     * Audio presentation content classifier: Voice over.
+     */
+    public static final int CONTENT_VOICEOVER               = 7;
+
+    /** @hide */
+    @IntDef(
+        value = {
             MASTERING_NOT_INDICATED,
             MASTERED_FOR_STEREO,
             MASTERED_FOR_SURROUND,
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index b196437..bf04b66 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -275,6 +275,12 @@
     private AudioAttributes mAudioAttributes;
     private boolean mIsSubmixFullVolume = false;
 
+    /**
+     * The log session id used for metrics.
+     * A null or empty string here means it is not set.
+     */
+    private String mLogSessionId;
+
     //---------------------------------------------------------
     // Constructor, Finalize
     //--------------------
@@ -1913,6 +1919,25 @@
         return native_set_preferred_microphone_field_dimension(zoom) == AudioSystem.SUCCESS;
     }
 
+    /**
+     * Sets a string handle to this AudioRecord for metrics collection.
+     *
+     * @param logSessionId a string which is used to identify this object
+     *        to the metrics service.  Proper generated Ids must be obtained
+     *        from the Java metrics service and should be considered opaque.
+     *        Use null to remove the logSessionId association.
+     * @throws IllegalStateException if AudioRecord not initialized.
+     *
+     * @hide
+     */
+    public void setLogSessionId(@Nullable String logSessionId) {
+        if (mState == STATE_UNINITIALIZED) {
+            throw new IllegalStateException("AudioRecord not initialized");
+        }
+        native_setLogSessionId(logSessionId);
+        mLogSessionId = logSessionId;
+    }
+
     //---------------------------------------------------------
     // Interface definitions
     //--------------------
@@ -2072,6 +2097,8 @@
     private native int native_set_preferred_microphone_direction(int direction);
     private native int native_set_preferred_microphone_field_dimension(float zoom);
 
+    private native void native_setLogSessionId(@Nullable String logSessionId);
+
     //---------------------------------------------------------
     // Utility methods
     //------------------
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 6fcb756..88731d2 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -567,6 +567,7 @@
 
     /**
      * The log session id used for metrics.
+     * A null or empty string here means it is not set.
      */
     private String mLogSessionId;
 
@@ -928,12 +929,21 @@
         private final int mSyncId;
 
         /**
+         * A special content id for {@link #TunerConfiguration(int, int)}
+         * indicating audio is delivered
+         * from an {@code AudioTrack} write, not tunneled from the tuner stack.
+         */
+        public static final int CONTENT_ID_NONE = 0;
+
+        /**
          * Constructs a TunerConfiguration instance for use in {@link AudioTrack.Builder}
          *
          * @param contentId selects the audio stream to use.
          *     The contentId may be obtained from
-         *     {@link android.media.tv.tuner.filter.Filter#getId()}.
-         *     This is always a positive number.
+         *     {@link android.media.tv.tuner.filter.Filter#getId()},
+         *     such obtained id is always a positive number.
+         *     If audio is to be delivered through an {@code AudioTrack} write
+         *     then {@code CONTENT_ID_NONE} may be used.
          * @param syncId selects the clock to use for synchronization
          *     of audio with other streams such as video.
          *     The syncId may be obtained from
@@ -942,10 +952,10 @@
          */
         @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
         public TunerConfiguration(
-                @IntRange(from = 1) int contentId, @IntRange(from = 1)int syncId) {
-            if (contentId < 1) {
+                @IntRange(from = 0) int contentId, @IntRange(from = 1)int syncId) {
+            if (contentId < 0) {
                 throw new IllegalArgumentException(
-                        "contentId " + contentId + " must be positive");
+                        "contentId " + contentId + " must be positive or CONTENT_ID_NONE");
             }
             if (syncId < 1) {
                 throw new IllegalArgumentException("syncId " + syncId + " must be positive");
@@ -3526,8 +3536,9 @@
                 native_enableDeviceCallback();
                 return true;
             } catch (IllegalStateException e) {
-                // Fail silently as track state could have changed in between start
-                // and enabling routing callback, return false to indicate not enabled
+                if (Log.isLoggable(TAG, Log.DEBUG)) {
+                    Log.d(TAG, "testEnableNativeRoutingCallbacks failed", e);
+                }
             }
         }
         return false;
@@ -3577,7 +3588,7 @@
             Handler handler) {
         synchronized (mRoutingChangeListeners) {
             if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
-                testEnableNativeRoutingCallbacksLocked();
+                mEnableSelfRoutingMonitor = testEnableNativeRoutingCallbacksLocked();
                 mRoutingChangeListeners.put(
                         listener, new NativeRoutingEventHandlerDelegate(this, listener,
                                 handler != null ? handler : new Handler(mInitializationLooper)));
@@ -3977,12 +3988,14 @@
      * Sets a string handle to this AudioTrack for metrics collection.
      *
      * @param logSessionId a string which is used to identify this object
-     *        to the metrics service.
+     *        to the metrics service.  Proper generated Ids must be obtained
+     *        from the Java metrics service and should be considered opaque.
+     *        Use null to remove the logSessionId association.
      * @throws IllegalStateException if AudioTrack not initialized.
      *
      * @hide
      */
-    public void setLogSessionId(@NonNull String logSessionId) {
+    public void setLogSessionId(@Nullable String logSessionId) {
         if (mState == STATE_UNINITIALIZED) {
             throw new IllegalStateException("track not initialized");
         }
@@ -4225,7 +4238,7 @@
     private native int native_get_audio_description_mix_level_db(float[] level);
     private native int native_set_dual_mono_mode(int dualMonoMode);
     private native int native_get_dual_mono_mode(int[] dualMonoMode);
-    private native void native_setLogSessionId(@NonNull String logSessionId);
+    private native void native_setLogSessionId(@Nullable String logSessionId);
 
     /**
      * Sets the audio service Player Interface Id.
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 4d7ed11..06d0eb0 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -19,6 +19,7 @@
 import static android.media.Utils.intersectSortedDistinctRanges;
 import static android.media.Utils.sortDistinctRanges;
 
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
@@ -1133,6 +1134,7 @@
          * in the ranges returned by {@link #getInputChannelCountRanges}
          *
          */
+        @IntRange(from = 1, to = 255)
         public int getMaxInputChannelCount() {
             int overall_max = 0;
             for (int i = mInputChannelRanges.length - 1; i >= 0; i--) {
@@ -1151,6 +1153,7 @@
          * This returns the lowest channel count in the ranges returned by
          * {@link #getInputChannelCountRanges}.
          */
+        @IntRange(from = 1, to = 255)
         public int getMinInputChannelCount() {
             int overall_min = MAX_INPUT_CHANNEL_COUNT;
             for (int i = mInputChannelRanges.length - 1; i >= 0; i--) {
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 67f1660..f8a642a 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -980,6 +980,74 @@
     public static final String KEY_BITRATE_MODE = "bitrate-mode";
 
     /**
+     * A key describing the maximum Quantization Parameter allowed for encoding video.
+     * This key applies to all three video frame types (I, P, and B). This value fills
+     * in for any of the frame-specific #KEY_VIDEO_QP_I_MAX, #KEY_VIDEO_QP_P_MAX, or
+     * #KEY_VIDEO_QP_B_MAX keys that are not specified
+     *
+     * The associated value is an integer.
+     */
+    public static final String KEY_VIDEO_QP_MAX = "video-qp-max";
+
+    /**
+     * A key describing the maximum Quantization Parameter allowed for encoding video.
+     * This key applies to all three video frame types (I, P, and B). This value fills
+     * in for any of the frame-specific #KEY_VIDEO_QP_I_MIN, #KEY_VIDEO_QP_P_MIN, or
+     * #KEY_VIDEO_QP_B_MIN keys that are not specified
+     *
+     * The associated value is an integer.
+     */
+    public static final String KEY_VIDEO_QP_MIN = "video-qp-min";
+
+    /**
+     * A key describing the maximum Quantization Parameter allowed for encoding video.
+     * This value applies to video I-frames.
+     *
+     * The associated value is an integer.
+     */
+    public static final String KEY_VIDEO_QP_I_MAX = "video-qp-i-max";
+
+    /**
+     * A key describing the minimum Quantization Parameter allowed for encoding video.
+     * This value applies to video I-frames.
+     *
+     * The associated value is an integer.
+     */
+    public static final String KEY_VIDEO_QP_I_MIN = "video-qp-i-min";
+
+    /**
+     * A key describing the maximum Quantization Parameter allowed for encoding video.
+     * This value applies to video P-frames.
+     *
+     * The associated value is an integer.
+     */
+    public static final String KEY_VIDEO_QP_P_MAX = "video-qp-p-max";
+
+    /**
+     * A key describing the minimum Quantization Parameter allowed for encoding video.
+     * This value applies to video P-frames.
+     *
+     * The associated value is an integer.
+     */
+    public static final String KEY_VIDEO_QP_P_MIN = "video-qp-p-min";
+
+    /**
+     * A key describing the maximum Quantization Parameter allowed for encoding video.
+     * This value applies to video B-frames.
+     *
+     * The associated value is an integer.
+     */
+    public static final String KEY_VIDEO_QP_B_MAX = "video-qp-b-max";
+
+    /**
+     * A key describing the minimum Quantization Parameter allowed for encoding video.
+     * This value applies to video B-frames.
+     *
+     * The associated value is an integer.
+     */
+    public static final String KEY_VIDEO_QP_B_MIN = "video-qp-b-min";
+
+    /**
      * A key describing the audio session ID of the AudioTrack associated
      * to a tunneled video codec.
      * The associated value is an integer.
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index f3cee17..9176dae 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1360,6 +1360,7 @@
     private void startImpl() {
         baseStart(0); // unknown device at this point
         stayAwake(true);
+        tryToEnableNativeRoutingCallback();
         _start();
     }
 
@@ -1385,6 +1386,7 @@
         stayAwake(false);
         _stop();
         baseStop();
+        tryToDisableNativeRoutingCallback();
     }
 
     private native void _stop() throws IllegalStateException;
@@ -1526,8 +1528,9 @@
                 native_enableDeviceCallback(true);
                 return true;
             } catch (IllegalStateException e) {
-                // Fail silently as media player state could have changed in between start
-                // and enabling routing callback, return false to indicate not enabled
+                if (Log.isLoggable(TAG, Log.DEBUG)) {
+                    Log.d(TAG, "testEnableNativeRoutingCallbacks failed", e);
+                }
             }
         }
         return false;
@@ -1590,7 +1593,7 @@
             Handler handler) {
         synchronized (mRoutingChangeListeners) {
             if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
-                testEnableNativeRoutingCallbacksLocked();
+                mEnableSelfRoutingMonitor = testEnableNativeRoutingCallbacksLocked();
                 mRoutingChangeListeners.put(
                         listener, new NativeRoutingEventHandlerDelegate(this, listener,
                                 handler != null ? handler : mEventHandler));
@@ -3483,9 +3486,6 @@
 
             case MEDIA_STOPPED:
                 {
-                    tryToDisableNativeRoutingCallback();
-                    // FIXME see b/179218630
-                    //baseStop();
                     TimeProvider timeProvider = mTimeProvider;
                     if (timeProvider != null) {
                         timeProvider.onStopped();
@@ -3494,18 +3494,9 @@
                 break;
 
             case MEDIA_STARTED:
-                {
-                    // FIXME see b/179218630
-                    //baseStart(native_getRoutedDeviceId());
-                    tryToEnableNativeRoutingCallback();
-                }
                 // fall through
             case MEDIA_PAUSED:
                 {
-                    // FIXME see b/179218630
-                    //if (msg.what == MEDIA_PAUSED) {
-                    //    basePause();
-                    //}
                     TimeProvider timeProvider = mTimeProvider;
                     if (timeProvider != null) {
                         timeProvider.onPaused(msg.what == MEDIA_PAUSED);
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index dc476b8..96bffee117 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -38,9 +38,7 @@
 interface ISessionManager {
     ISession createSession(String packageName, in ISessionCallback sessionCb, String tag,
             in Bundle sessionInfo, int userId);
-    void notifySession2Created(in Session2Token sessionToken);
     List<MediaSession.Token> getSessions(in ComponentName compName, int userId);
-    ParceledListSlice getSession2Tokens(int userId);
     void dispatchMediaKeyEvent(String packageName, boolean asSystemService, in KeyEvent keyEvent,
             boolean needWakeLock);
     boolean dispatchMediaKeyEventToSessionAsSystemService(String packageName,
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index aa0f7fd..98a13cf 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -25,9 +25,9 @@
 import android.annotation.SystemService;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.pm.ParceledListSlice;
 import android.media.AudioManager;
 import android.media.IRemoteSessionCallback;
+import android.media.MediaCommunicationManager;
 import android.media.MediaFrameworkPlatformInitializer;
 import android.media.MediaSession2;
 import android.media.Session2Token;
@@ -84,6 +84,7 @@
     public static final int RESULT_MEDIA_KEY_HANDLED = 1;
 
     private final ISessionManager mService;
+    private final MediaCommunicationManager mCommunicationManager;
     private final OnMediaKeyEventDispatchedListenerStub mOnMediaKeyEventDispatchedListenerStub =
             new OnMediaKeyEventDispatchedListenerStub();
     private final OnMediaKeyEventSessionChangedListenerStub
@@ -128,6 +129,8 @@
                 .getMediaServiceManager()
                 .getMediaSessionServiceRegisterer()
                 .get());
+        mCommunicationManager = (MediaCommunicationManager) context
+                .getSystemService(Context.MEDIA_COMMUNICATION_SERVICE);
     }
 
     /**
@@ -164,17 +167,11 @@
      * {@link MediaSession2.Builder} instead.
      *
      * @param token newly created session2 token
+     * @deprecated Don't use this method. A new media session is notified automatically.
      */
+    @Deprecated
     public void notifySession2Created(@NonNull Session2Token token) {
-        Objects.requireNonNull(token, "token shouldn't be null");
-        if (token.getType() != Session2Token.TYPE_SESSION) {
-            throw new IllegalArgumentException("token's type should be TYPE_SESSION");
-        }
-        try {
-            mService.notifySession2Created(token);
-        } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-        }
+        // Does nothing
     }
 
     /**
@@ -255,37 +252,7 @@
      */
     @NonNull
     public List<Session2Token> getSession2Tokens() {
-        return getSession2Tokens(UserHandle.myUserId());
-    }
-
-    /**
-     * Gets a list of {@link Session2Token} with type {@link Session2Token#TYPE_SESSION} for the
-     * given user.
-     * <p>
-     * The calling application needs to hold the
-     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission in order to
-     * retrieve session tokens for user ids that do not belong to current process.
-     *
-     * @param userHandle The user handle to fetch sessions for.
-     * @return A list of {@link Session2Token}
-     * @hide
-     */
-    @NonNull
-    @SuppressLint("UserHandle")
-    public List<Session2Token> getSession2Tokens(@NonNull UserHandle userHandle) {
-        Objects.requireNonNull(userHandle, "userHandle shouldn't be null");
-        return getSession2Tokens(userHandle.getIdentifier());
-
-    }
-
-    private List<Session2Token> getSession2Tokens(int userId) {
-        try {
-            ParceledListSlice slice = mService.getSession2Tokens(userId);
-            return slice == null ? new ArrayList<>() : slice.getList();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to get session tokens", e);
-        }
-        return new ArrayList<>();
+        return mCommunicationManager.getSession2Tokens();
     }
 
     /**
@@ -534,8 +501,7 @@
         }
         if (shouldRegisterCallback) {
             try {
-                mService.registerRemoteSessionCallback(
-                        mRemoteSessionCallbackStub);
+                mService.registerRemoteSessionCallback(mRemoteSessionCallbackStub);
             } catch (RemoteException e) {
                 Log.e(TAG, "Failed to register remote volume controller callback", e);
             }
diff --git a/media/java/android/media/soundtrigger/OWNERS b/media/java/android/media/soundtrigger/OWNERS
index 6a351d3..e5d0370 100644
--- a/media/java/android/media/soundtrigger/OWNERS
+++ b/media/java/android/media/soundtrigger/OWNERS
@@ -1 +1,2 @@
+ytai@google.com
 elaurent@google.com
diff --git a/media/java/android/mtp/MtpServer.java b/media/java/android/mtp/MtpServer.java
index 042d02f..1d2657a 100644
--- a/media/java/android/mtp/MtpServer.java
+++ b/media/java/android/mtp/MtpServer.java
@@ -144,11 +144,6 @@
         native_remove_storage(storage.getStorageId());
     }
 
-    public static void configure(boolean usePtp) {
-        native_configure(usePtp);
-    }
-
-    public static native final void native_configure(boolean usePtp);
     private native final void native_setup(
             MtpDatabase database,
             FileDescriptor controlFd,
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 177b00a..7562d39 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -226,7 +226,6 @@
     } else {
         ALOGE("LnbClientCallbackImpl::onEvent:"
                 "Lnb object has been freed. Ignoring callback.");
-        env->DeleteWeakGlobalRef(mLnbObj);
     }
 }
 
@@ -245,7 +244,6 @@
     } else {
         ALOGE("LnbClientCallbackImpl::onDiseqcMessage:"
                 "Lnb object has been freed. Ignoring callback.");
-        env->DeleteWeakGlobalRef(mLnbObj);
     }
 }
 
@@ -276,7 +274,6 @@
     } else {
         ALOGE("DvrClientCallbackImpl::onRecordStatus:"
                 "Dvr object has been freed. Ignoring callback.");
-        env->DeleteWeakGlobalRef(mDvrObj);
     }
 }
 
@@ -292,7 +289,6 @@
     } else {
         ALOGE("DvrClientCallbackImpl::onPlaybackStatus:"
                 "Dvr object has been freed. Ignoring callback.");
-        env->DeleteWeakGlobalRef(mDvrObj);
     }
 }
 
@@ -565,7 +561,7 @@
                 const std::vector<DemuxFilterEventExt::Event>& eventsExt) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/TsRecordEvent");
-    jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IIIJJ)V");
+    jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IIIJJI)V");
 
     for (int i = 0; i < events.size(); i++) {
         auto event = events[i];
@@ -618,7 +614,7 @@
                 const std::vector<DemuxFilterEventExt::Event>& eventsExt) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/MmtpRecordEvent");
-    jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IJIJ)V");
+    jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IJIJII)V");
 
     for (int i = 0; i < events.size(); i++) {
         auto event = events[i];
@@ -846,7 +842,6 @@
     } else {
         ALOGE("FilterClientCallbackImpl::onFilterEvent_1_1:"
                 "Filter object has been freed. Ignoring callback.");
-        env->DeleteWeakGlobalRef(mFilterObj);
     }
 }
 
@@ -871,7 +866,6 @@
     } else {
         ALOGE("FilterClientCallbackImpl::onFilterStatus:"
                 "Filter object has been freed. Ignoring callback.");
-        env->DeleteWeakGlobalRef(mFilterObj);
     }
 }
 
@@ -907,7 +901,6 @@
     } else {
         ALOGE("FrontendClientCallbackImpl::onEvent:"
                 "Frontend object has been freed. Ignoring callback.");
-        env->DeleteWeakGlobalRef(mObject);
     }
 }
 
@@ -920,7 +913,6 @@
     if (env->IsSameObject(frontend, nullptr)) {
         ALOGE("FrontendClientCallbackImpl::onScanMessage:"
                 "Frontend object has been freed. Ignoring callback.");
-        env->DeleteWeakGlobalRef(mObject);
         return;
     }
     switch(type) {
@@ -1078,7 +1070,6 @@
     if (env->IsSameObject(frontend, nullptr)) {
         ALOGE("FrontendClientCallbackImpl::onScanMessageExt1_1:"
                 "Frontend object has been freed. Ignoring callback.");
-        env->DeleteWeakGlobalRef(mObject);
         return;
     }
     switch(type) {
@@ -1137,7 +1128,7 @@
             bool isHighPriority = message.isHighPriority();
             env->CallVoidMethod(
                     frontend,
-                    env->GetMethodID(clazz, "onPriorityReported", "(B)V"),
+                    env->GetMethodID(clazz, "onPriorityReported", "(Z)V"),
                     isHighPriority);
             break;
         }
@@ -1243,7 +1234,6 @@
     if (env->IsSameObject(tuner, nullptr)) {
         ALOGE("openFrontendByHandle"
                 "Tuner object has been freed. Failed to open frontend.");
-        env->DeleteWeakGlobalRef(mObject);
         return NULL;
     }
 
@@ -2211,6 +2201,10 @@
                         intBandwidth = static_cast<jint>(bandwidth.dvbt());
                         break;
                     }
+                    case FrontendBandwidth::hidl_discriminator::dvbc: {
+                        intBandwidth = static_cast<jint>(bandwidth.dvbc());
+                        break;
+                    }
                     case FrontendBandwidth::hidl_discriminator::isdbt: {
                         intBandwidth = static_cast<jint>(bandwidth.isdbt());
                         break;
@@ -2731,12 +2725,10 @@
     FrontendDvbsVcmMode vcmMode =
             static_cast<FrontendDvbsVcmMode>(
                     env->GetIntField(settings, env->GetFieldID(clazz, "mVcmMode", "I")));
-    FrontendDvbsCodeRate coderate = getDvbsCodeRate(env, settings);
 
     FrontendDvbsSettings frontendDvbsSettings {
             .frequency = freq,
             .modulation = modulation,
-            .coderate = coderate,
             .symbolRate = symbolRate,
             .rolloff = rolloff,
             .pilot = pilot,
@@ -2744,6 +2736,13 @@
             .standard = standard,
             .vcmMode = vcmMode,
     };
+
+    jobject jcodeRate = env->GetObjectField(settings, env->GetFieldID(clazz, "mCodeRate",
+            "Landroid/media/tv/tuner/frontend/DvbsCodeRate;"));
+    if (jcodeRate != NULL) {
+        frontendDvbsSettings.coderate = getDvbsCodeRate(env, settings);
+    }
+
     frontendSettings.dvbs(frontendDvbsSettings);
     return frontendSettings;
 }
@@ -2755,7 +2754,7 @@
             static_cast<FrontendDvbsScanType>(
                     env->GetIntField(settings, env->GetFieldID(clazz, "mScanType", "I")));
     bool isDiseqcRxMessage = static_cast<bool>(env->GetBooleanField(
-            settings, env->GetFieldID(clazz, "mIsDiseqcRxMessage", "B")));
+            settings, env->GetFieldID(clazz, "mIsDiseqcRxMessage", "Z")));
 
     FrontendDvbsSettingsExt1_1 dvbsExt1_1 {
         .scanType = scanType,
@@ -2995,6 +2994,10 @@
 static FrontendSettings getFrontendSettings(JNIEnv *env, int type, jobject settings) {
     ALOGD("getFrontendSettings %d", type);
 
+    if (type == static_cast<int>(::android::hardware::tv::tuner::V1_1::FrontendType::DTMB)) {
+        return FrontendSettings();
+    }
+
     FrontendType feType = static_cast<FrontendType>(type);
     switch(feType) {
         case FrontendType::ANALOG:
@@ -3568,26 +3571,28 @@
                 .tpid = tpid,
             };
 
-            DemuxTsFilterType tsType = static_cast<DemuxTsFilterType>(subtype);
-            switch (tsType) {
-                case DemuxTsFilterType::SECTION:
-                    tsFilterSettings.filterSettings.section(
-                            getFilterSectionSettings(env, settingsObj));
-                    break;
-                case DemuxTsFilterType::AUDIO:
-                case DemuxTsFilterType::VIDEO:
-                    tsFilterSettings.filterSettings.av(getFilterAvSettings(env, settingsObj));
-                    break;
-                case DemuxTsFilterType::PES:
-                    tsFilterSettings.filterSettings.pesData(
-                            getFilterPesDataSettings(env, settingsObj));
-                    break;
-                case DemuxTsFilterType::RECORD:
-                    tsFilterSettings.filterSettings.record(
-                            getFilterRecordSettings(env, settingsObj));
-                    break;
-                default:
-                    break;
+            if (settingsObj != NULL) {
+                DemuxTsFilterType tsType = static_cast<DemuxTsFilterType>(subtype);
+                switch (tsType) {
+                    case DemuxTsFilterType::SECTION:
+                        tsFilterSettings.filterSettings.section(
+                                getFilterSectionSettings(env, settingsObj));
+                        break;
+                    case DemuxTsFilterType::AUDIO:
+                    case DemuxTsFilterType::VIDEO:
+                        tsFilterSettings.filterSettings.av(getFilterAvSettings(env, settingsObj));
+                        break;
+                    case DemuxTsFilterType::PES:
+                        tsFilterSettings.filterSettings.pesData(
+                                getFilterPesDataSettings(env, settingsObj));
+                        break;
+                    case DemuxTsFilterType::RECORD:
+                        tsFilterSettings.filterSettings.record(
+                                getFilterRecordSettings(env, settingsObj));
+                        break;
+                    default:
+                        break;
+                }
             }
             filterSettings.ts(tsFilterSettings);
             break;
@@ -3599,60 +3604,55 @@
             DemuxMmtpFilterSettings mmtpFilterSettings {
                 .mmtpPid = mmtpPid,
             };
-            DemuxMmtpFilterType mmtpType = static_cast<DemuxMmtpFilterType>(subtype);
-            switch (mmtpType) {
-                case DemuxMmtpFilterType::SECTION:
-                    mmtpFilterSettings.filterSettings.section(
-                            getFilterSectionSettings(env, settingsObj));
-                    break;
-                case DemuxMmtpFilterType::AUDIO:
-                case DemuxMmtpFilterType::VIDEO:
-                    mmtpFilterSettings.filterSettings.av(getFilterAvSettings(env, settingsObj));
-                    break;
-                case DemuxMmtpFilterType::PES:
-                    mmtpFilterSettings.filterSettings.pesData(
-                            getFilterPesDataSettings(env, settingsObj));
-                    break;
-                case DemuxMmtpFilterType::RECORD:
-                    mmtpFilterSettings.filterSettings.record(
-                            getFilterRecordSettings(env, settingsObj));
-                    break;
-                case DemuxMmtpFilterType::DOWNLOAD:
-                    mmtpFilterSettings.filterSettings.download(
-                            getFilterDownloadSettings(env, settingsObj));
-                    break;
-                default:
-                    break;
+
+            if (settingsObj != NULL) {
+                DemuxMmtpFilterType mmtpType = static_cast<DemuxMmtpFilterType>(subtype);
+                switch (mmtpType) {
+                    case DemuxMmtpFilterType::SECTION:
+                        mmtpFilterSettings.filterSettings.section(
+                                getFilterSectionSettings(env, settingsObj));
+                        break;
+                    case DemuxMmtpFilterType::AUDIO:
+                    case DemuxMmtpFilterType::VIDEO:
+                        mmtpFilterSettings.filterSettings.av(getFilterAvSettings(env, settingsObj));
+                        break;
+                    case DemuxMmtpFilterType::PES:
+                        mmtpFilterSettings.filterSettings.pesData(
+                                getFilterPesDataSettings(env, settingsObj));
+                        break;
+                    case DemuxMmtpFilterType::RECORD:
+                        mmtpFilterSettings.filterSettings.record(
+                                getFilterRecordSettings(env, settingsObj));
+                        break;
+                    case DemuxMmtpFilterType::DOWNLOAD:
+                        mmtpFilterSettings.filterSettings.download(
+                                getFilterDownloadSettings(env, settingsObj));
+                        break;
+                    default:
+                        break;
+                }
             }
             filterSettings.mmtp(mmtpFilterSettings);
             break;
         }
         case DemuxFilterMainType::IP: {
             DemuxIpAddress ipAddr = getDemuxIpAddress(env, filterConfigObj);
-
             DemuxIpFilterSettings ipFilterSettings {
                 .ipAddr = ipAddr,
             };
+
             DemuxIpFilterType ipType = static_cast<DemuxIpFilterType>(subtype);
-            switch (ipType) {
-                case DemuxIpFilterType::SECTION: {
-                    ipFilterSettings.filterSettings.section(
-                            getFilterSectionSettings(env, settingsObj));
-                    break;
-                }
-                case DemuxIpFilterType::IP: {
-                    jclass clazz = env->FindClass(
-                            "android/media/tv/tuner/filter/IpFilterConfiguration");
-                    bool bPassthrough = static_cast<bool>(
-                            env->GetBooleanField(
-                                    filterConfigObj, env->GetFieldID(
-                                            clazz, "mPassthrough", "Z")));
-                    ipFilterSettings.filterSettings.bPassthrough(bPassthrough);
-                    break;
-                }
-                default: {
-                    break;
-                }
+            if (ipType == DemuxIpFilterType::SECTION && settingsObj != NULL) {
+                ipFilterSettings.filterSettings.section(
+                                getFilterSectionSettings(env, settingsObj));
+            } else if (ipType == DemuxIpFilterType::IP) {
+                jclass clazz = env->FindClass(
+                        "android/media/tv/tuner/filter/IpFilterConfiguration");
+                bool bPassthrough = static_cast<bool>(
+                        env->GetBooleanField(
+                                filterConfigObj, env->GetFieldID(
+                                        clazz, "mPassthrough", "Z")));
+                ipFilterSettings.filterSettings.bPassthrough(bPassthrough);
             }
             filterSettings.ip(ipFilterSettings);
             break;
@@ -3669,24 +3669,17 @@
                 .packetType = packetType,
                 .isCompressedIpPacket = isCompressedIpPacket,
             };
+
             DemuxTlvFilterType tlvType = static_cast<DemuxTlvFilterType>(subtype);
-            switch (tlvType) {
-                case DemuxTlvFilterType::SECTION: {
-                    tlvFilterSettings.filterSettings.section(
-                            getFilterSectionSettings(env, settingsObj));
-                    break;
-                }
-                case DemuxTlvFilterType::TLV: {
-                    bool bPassthrough = static_cast<bool>(
-                            env->GetBooleanField(
-                                    filterConfigObj, env->GetFieldID(
-                                            clazz, "mPassthrough", "Z")));
-                    tlvFilterSettings.filterSettings.bPassthrough(bPassthrough);
-                    break;
-                }
-                default: {
-                    break;
-                }
+            if (tlvType == DemuxTlvFilterType::SECTION && settingsObj != NULL) {
+                tlvFilterSettings.filterSettings.section(
+                        getFilterSectionSettings(env, settingsObj));
+            } else if (tlvType == DemuxTlvFilterType::TLV) {
+                bool bPassthrough = static_cast<bool>(
+                env->GetBooleanField(
+                        filterConfigObj, env->GetFieldID(
+                                clazz, "mPassthrough", "Z")));
+                tlvFilterSettings.filterSettings.bPassthrough(bPassthrough);
             }
             filterSettings.tlv(tlvFilterSettings);
             break;
@@ -3701,14 +3694,17 @@
                 .packetType = packetType,
                 .lengthType = lengthType,
             };
-            DemuxAlpFilterType alpType = static_cast<DemuxAlpFilterType>(subtype);
-            switch (alpType) {
-                case DemuxAlpFilterType::SECTION:
-                    alpFilterSettings.filterSettings.section(
-                            getFilterSectionSettings(env, settingsObj));
-                    break;
-                default:
-                    break;
+
+            if (settingsObj != NULL) {
+                DemuxAlpFilterType alpType = static_cast<DemuxAlpFilterType>(subtype);
+                switch (alpType) {
+                    case DemuxAlpFilterType::SECTION:
+                        alpFilterSettings.filterSettings.section(
+                                getFilterSectionSettings(env, settingsObj));
+                        break;
+                    default:
+                        break;
+                }
             }
             filterSettings.alp(alpFilterSettings);
             break;
diff --git a/media/jni/tuner/FrontendClient.cpp b/media/jni/tuner/FrontendClient.cpp
index f400a71..f54e266 100644
--- a/media/jni/tuner/FrontendClient.cpp
+++ b/media/jni/tuner/FrontendClient.cpp
@@ -588,14 +588,15 @@
                 break;
             }
             case TunerFrontendStatus::codeRates: {
-                int size = s.get<TunerFrontendStatus::codeRates>().size();
-                status.codeRates().resize(size);
-                for (int i = 0; i < size; i++) {
-                    auto aidlCodeRate = s.get<TunerFrontendStatus::codeRates>()[i];
-                    status.codeRates()[i] =
-                            static_cast<hardware::tv::tuner::V1_1::FrontendInnerFec>(aidlCodeRate);
+                vector<hardware::tv::tuner::V1_1::FrontendInnerFec> codeRates;
+                for (auto aidlCodeRate : s.get<TunerFrontendStatus::codeRates>()) {
+                    codeRates.push_back(
+                            static_cast<hardware::tv::tuner::V1_1::FrontendInnerFec>(aidlCodeRate));
                 }
-                hidlStatus.push_back(status);
+                if (codeRates.size() > 0) {
+                    status.codeRates(codeRates);
+                    hidlStatus.push_back(status);
+                }
                 break;
             }
             case TunerFrontendStatus::bandwidth: {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/AudioAttributesUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/AudioAttributesUnitTest.java
new file mode 100644
index 0000000..3a4bec0
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/AudioAttributesUnitTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.mediaframeworktest.unit;
+
+import static org.junit.Assert.assertEquals;
+
+import android.media.AudioAttributes;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class AudioAttributesUnitTest {
+
+    @Test
+    public void testUsageToString_returnCorrectStrings() {
+        assertEquals("USAGE_UNKNOWN", AudioAttributes.usageToString(AudioAttributes.USAGE_UNKNOWN));
+        assertEquals("USAGE_MEDIA", AudioAttributes.usageToString(AudioAttributes.USAGE_MEDIA));
+        assertEquals("USAGE_VOICE_COMMUNICATION",
+                AudioAttributes.usageToString(AudioAttributes.USAGE_VOICE_COMMUNICATION));
+        assertEquals("USAGE_VOICE_COMMUNICATION_SIGNALLING",
+                AudioAttributes.usageToString(
+                        AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING));
+        assertEquals("USAGE_ALARM", AudioAttributes.usageToString(AudioAttributes.USAGE_ALARM));
+        assertEquals("USAGE_NOTIFICATION",
+                AudioAttributes.usageToString(AudioAttributes.USAGE_NOTIFICATION));
+        assertEquals("USAGE_NOTIFICATION_RINGTONE",
+                AudioAttributes.usageToString(AudioAttributes.USAGE_NOTIFICATION_RINGTONE));
+        assertEquals("USAGE_NOTIFICATION_COMMUNICATION_REQUEST",
+                AudioAttributes.usageToString(
+                        AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST));
+        assertEquals("USAGE_NOTIFICATION_COMMUNICATION_INSTANT",
+                AudioAttributes.usageToString(
+                        AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT));
+        assertEquals("USAGE_NOTIFICATION_COMMUNICATION_DELAYED",
+                AudioAttributes.usageToString(
+                        AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED));
+        assertEquals("USAGE_NOTIFICATION_EVENT",
+                AudioAttributes.usageToString(AudioAttributes.USAGE_NOTIFICATION_EVENT));
+        assertEquals("USAGE_ASSISTANCE_ACCESSIBILITY",
+                AudioAttributes.usageToString(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY));
+        assertEquals("USAGE_ASSISTANCE_NAVIGATION_GUIDANCE",
+                AudioAttributes.usageToString(
+                        AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE));
+        assertEquals("USAGE_ASSISTANCE_SONIFICATION",
+                AudioAttributes.usageToString(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION));
+        assertEquals("USAGE_GAME", AudioAttributes.usageToString(AudioAttributes.USAGE_GAME));
+        assertEquals("USAGE_ASSISTANT",
+                AudioAttributes.usageToString(AudioAttributes.USAGE_ASSISTANT));
+        assertEquals("USAGE_CALL_ASSISTANT",
+                AudioAttributes.usageToString(AudioAttributes.USAGE_CALL_ASSISTANT));
+        assertEquals("USAGE_EMERGENCY",
+                AudioAttributes.usageToString(AudioAttributes.USAGE_EMERGENCY));
+        assertEquals("USAGE_SAFETY", AudioAttributes.usageToString(AudioAttributes.USAGE_SAFETY));
+        assertEquals("USAGE_VEHICLE_STATUS",
+                AudioAttributes.usageToString(AudioAttributes.USAGE_VEHICLE_STATUS));
+        assertEquals("USAGE_ANNOUNCEMENT",
+                AudioAttributes.usageToString(AudioAttributes.USAGE_ANNOUNCEMENT));
+    }
+
+    @Test
+    public void testUsageToString_unknownUsage() {
+        assertEquals("unknown usage -1", AudioAttributes.usageToString(-1));
+    }
+}
diff --git a/native/android/tests/activitymanager/UidImportanceHelperApps/Android.bp b/native/android/tests/activitymanager/UidImportanceHelperApps/Android.bp
index 1a51218..fdca3fa 100644
--- a/native/android/tests/activitymanager/UidImportanceHelperApps/Android.bp
+++ b/native/android/tests/activitymanager/UidImportanceHelperApps/Android.bp
@@ -1,3 +1,12 @@
+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_test_helper_app {
     name: "UidImportanceHelperApp",
     manifest: "HelperAppManifest.xml",
@@ -8,4 +17,3 @@
         "general-tests",
     ],
 }
-
diff --git a/native/android/tests/activitymanager/nativeTests/Android.bp b/native/android/tests/activitymanager/nativeTests/Android.bp
index d4b5015..528ac12 100644
--- a/native/android/tests/activitymanager/nativeTests/Android.bp
+++ b/native/android/tests/activitymanager/nativeTests/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
 cc_test {
     name: "ActivityManagerNativeTestCases",
 
diff --git a/packages/CompanionDeviceManager/AndroidManifest.xml b/packages/CompanionDeviceManager/AndroidManifest.xml
index 91bad7b..f9795c6 100644
--- a/packages/CompanionDeviceManager/AndroidManifest.xml
+++ b/packages/CompanionDeviceManager/AndroidManifest.xml
@@ -41,13 +41,13 @@
         android:supportsRtl="true">
 
         <service
-            android:name=".DeviceDiscoveryService"
+            android:name=".CompanionDeviceDiscoveryService"
             android:permission="android.permission.BIND_COMPANION_DEVICE_MANAGER_SERVICE"
             android:exported="true">
         </service>
 
         <activity
-            android:name=".DeviceChooserActivity"
+            android:name=".CompanionDeviceActivity"
             android:theme="@style/ChooserActivity"
             android:permission="android.permission.BIND_COMPANION_DEVICE_MANAGER_SERVICE"
             android:exported="true">
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
similarity index 62%
rename from packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
rename to packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index c30d4bf..f1a98ad 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -24,6 +24,7 @@
 
 import static java.util.Objects.requireNonNull;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.companion.AssociationRequest;
@@ -31,41 +32,52 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.database.DataSetObserver;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.text.Html;
 import android.util.Log;
+import android.util.SparseArray;
+import android.util.TypedValue;
 import android.view.Gravity;
 import android.view.View;
-import android.widget.AdapterView;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
 import android.widget.ListView;
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
-import com.android.companiondevicemanager.DeviceDiscoveryService.DeviceFilterPair;
+import com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DeviceFilterPair;
 import com.android.internal.util.Preconditions;
 
-public class DeviceChooserActivity extends Activity {
+public class CompanionDeviceActivity extends Activity {
 
     private static final boolean DEBUG = false;
-    private static final String LOG_TAG = "DeviceChooserActivity";
+    private static final String LOG_TAG = CompanionDeviceActivity.class.getSimpleName();
+
+    static CompanionDeviceActivity sInstance;
 
     View mLoadingIndicator = null;
     ListView mDeviceListView;
     private View mPairButton;
     private View mCancelButton;
 
+    DevicesAdapter mDevicesAdapter;
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        if (DEBUG) Log.i(LOG_TAG, "Started with intent " + getIntent());
+        Log.i(LOG_TAG, "Starting UI for " + getService().mRequest);
 
         if (getService().mDevicesFound.isEmpty()) {
             Log.e(LOG_TAG, "About to show UI, but no devices to show");
         }
 
         getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+        sInstance = this;
 
         String deviceProfile = getRequest().getDeviceProfile();
         String profilePrivacyDisclaimer = emptyIfNull(getRequest()
@@ -96,17 +108,14 @@
                     profileName,
                     getCallingAppName()), 0));
             mDeviceListView = findViewById(R.id.device_list);
-            final DeviceDiscoveryService.DevicesAdapter adapter = getService().mDevicesAdapter;
-            mDeviceListView.setAdapter(adapter);
-            mDeviceListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
-                @Override
-                public void onItemClick(AdapterView<?> adapterView, View view, int pos, long l) {
-                    getService().mSelectedDevice =
-                            (DeviceFilterPair) adapterView.getItemAtPosition(pos);
-                    adapter.notifyDataSetChanged();
-                }
+            mDevicesAdapter = new DevicesAdapter();
+            mDeviceListView.setAdapter(mDevicesAdapter);
+            mDeviceListView.setOnItemClickListener((adapterView, view, pos, l) -> {
+                getService().mSelectedDevice =
+                        (DeviceFilterPair) adapterView.getItemAtPosition(pos);
+                mDevicesAdapter.notifyDataSetChanged();
             });
-            adapter.registerDataSetObserver(new DataSetObserver() {
+            mDevicesAdapter.registerDataSetObserver(new DataSetObserver() {
                 @Override
                 public void onChanged() {
                     onSelectionUpdate();
@@ -133,6 +142,12 @@
         mCancelButton.setOnClickListener(v -> cancel());
     }
 
+    static void notifyDevicesChanged() {
+        if (sInstance != null && sInstance.mDevicesAdapter != null && !sInstance.isFinishing()) {
+            sInstance.mDevicesAdapter.notifyDataSetChanged();
+        }
+    }
+
     private AssociationRequest getRequest() {
         return getService().mRequest;
     }
@@ -156,6 +171,7 @@
     }
 
     private void cancel() {
+        Log.i(LOG_TAG, "cancel()");
         getService().onCancel();
         setResult(RESULT_CANCELED);
         finish();
@@ -170,6 +186,14 @@
         }
     }
 
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        if (sInstance == this) {
+            sInstance = null;
+        }
+    }
+
     private CharSequence getCallingAppName() {
         try {
             final PackageManager packageManager = getPackageManager();
@@ -217,15 +241,91 @@
         }
     }
 
-    private DeviceDiscoveryService getService() {
-        return DeviceDiscoveryService.sInstance;
+    private CompanionDeviceDiscoveryService getService() {
+        return CompanionDeviceDiscoveryService.sInstance;
     }
 
-   protected void onDeviceConfirmed(DeviceFilterPair selectedDevice) {
+    protected void onDeviceConfirmed(DeviceFilterPair selectedDevice) {
+        Log.i(LOG_TAG, "onDeviceConfirmed(selectedDevice = " + selectedDevice + ")");
         getService().onDeviceSelected(
                 getCallingPackage(), getDeviceMacAddress(selectedDevice.device));
         setResult(RESULT_OK,
                 new Intent().putExtra(CompanionDeviceManager.EXTRA_DEVICE, selectedDevice.device));
         finish();
     }
+
+    class DevicesAdapter extends BaseAdapter {
+        private final Drawable mBluetoothIcon = icon(android.R.drawable.stat_sys_data_bluetooth);
+        private final Drawable mWifiIcon = icon(com.android.internal.R.drawable.ic_wifi_signal_3);
+
+        private SparseArray<Integer> mColors = new SparseArray();
+
+        private Drawable icon(int drawableRes) {
+            Drawable icon = getResources().getDrawable(drawableRes, null);
+            icon.setTint(Color.DKGRAY);
+            return icon;
+        }
+
+        @Override
+        public View getView(
+                int position,
+                @Nullable View convertView,
+                @NonNull ViewGroup parent) {
+            TextView view = convertView instanceof TextView
+                    ? (TextView) convertView
+                    : newView();
+            bind(view, getItem(position));
+            return view;
+        }
+
+        private void bind(TextView textView, DeviceFilterPair device) {
+            textView.setText(device.getDisplayName());
+            textView.setBackgroundColor(
+                    device.equals(getService().mSelectedDevice)
+                            ? getColor(android.R.attr.colorControlHighlight)
+                            : Color.TRANSPARENT);
+            textView.setCompoundDrawablesWithIntrinsicBounds(
+                    device.device instanceof android.net.wifi.ScanResult
+                            ? mWifiIcon
+                            : mBluetoothIcon,
+                    null, null, null);
+            textView.getCompoundDrawables()[0].setTint(getColor(android.R.attr.colorForeground));
+        }
+
+        private TextView newView() {
+            final TextView textView = new TextView(CompanionDeviceActivity.this);
+            textView.setTextColor(getColor(android.R.attr.colorForeground));
+            final int padding = CompanionDeviceActivity.getPadding(getResources());
+            textView.setPadding(padding, padding, padding, padding);
+            textView.setCompoundDrawablePadding(padding);
+            return textView;
+        }
+
+        private int getColor(int colorAttr) {
+            if (mColors.contains(colorAttr)) {
+                return mColors.get(colorAttr);
+            }
+            TypedValue typedValue = new TypedValue();
+            TypedArray a = obtainStyledAttributes(typedValue.data, new int[] { colorAttr });
+            int result = a.getColor(0, 0);
+            a.recycle();
+            mColors.put(colorAttr, result);
+            return result;
+        }
+
+        @Override
+        public int getCount() {
+            return getService().mDevicesFound.size();
+        }
+
+        @Override
+        public DeviceFilterPair getItem(int position) {
+            return getService().mDevicesFound.get(position);
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+    }
 }
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
similarity index 77%
rename from packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
rename to packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
index 67d4b41..8b44887 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
@@ -50,9 +50,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.res.TypedArray;
-import android.graphics.Color;
-import android.graphics.drawable.Drawable;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
 import android.os.IBinder;
@@ -60,12 +57,6 @@
 import android.os.RemoteException;
 import android.text.TextUtils;
 import android.util.Log;
-import android.util.SparseArray;
-import android.util.TypedValue;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.TextView;
 
 import com.android.internal.infra.AndroidFuture;
 import com.android.internal.util.ArrayUtils;
@@ -76,14 +67,14 @@
 import java.util.List;
 import java.util.Objects;
 
-public class DeviceDiscoveryService extends Service {
+public class CompanionDeviceDiscoveryService extends Service {
 
     private static final boolean DEBUG = false;
-    private static final String LOG_TAG = "DeviceDiscoveryService";
+    private static final String LOG_TAG = CompanionDeviceDiscoveryService.class.getSimpleName();
 
     private static final long SCAN_TIMEOUT = 20000;
 
-    static DeviceDiscoveryService sInstance;
+    static CompanionDeviceDiscoveryService sInstance;
 
     private BluetoothManager mBluetoothManager;
     private BluetoothAdapter mBluetoothAdapter;
@@ -102,12 +93,12 @@
     AssociationRequest mRequest;
     List<DeviceFilterPair> mDevicesFound;
     DeviceFilterPair mSelectedDevice;
-    DevicesAdapter mDevicesAdapter;
     IFindDeviceCallback mFindCallback;
 
     AndroidFuture<Association> mServiceCallback;
     boolean mIsScanning = false;
-    @Nullable DeviceChooserActivity mActivity = null;
+    @Nullable
+    CompanionDeviceActivity mActivity = null;
 
     private final ICompanionDeviceDiscoveryService mBinder =
             new ICompanionDeviceDiscoveryService.Stub() {
@@ -116,16 +107,15 @@
                 String callingPackage,
                 IFindDeviceCallback findCallback,
                 AndroidFuture serviceCallback) {
-            if (DEBUG) {
-                Log.i(LOG_TAG,
-                        "startDiscovery() called with: filter = [" + request
-                                + "], findCallback = [" + findCallback + "]"
-                                + "], serviceCallback = [" + serviceCallback + "]");
-            }
+            Log.i(LOG_TAG,
+                    "startDiscovery() called with: filter = [" + request
+                            + "], findCallback = [" + findCallback + "]"
+                            + "], serviceCallback = [" + serviceCallback + "]");
             mFindCallback = findCallback;
             mServiceCallback = serviceCallback;
             Handler.getMain().sendMessage(obtainMessage(
-                    DeviceDiscoveryService::startDiscovery, DeviceDiscoveryService.this, request));
+                    CompanionDeviceDiscoveryService::startDiscovery,
+                    CompanionDeviceDiscoveryService.this, request));
         }
     };
 
@@ -135,7 +125,7 @@
 
     @Override
     public IBinder onBind(Intent intent) {
-        if (DEBUG) Log.i(LOG_TAG, "onBind(" + intent + ")");
+        Log.i(LOG_TAG, "onBind(" + intent + ")");
         return mBinder.asBinder();
     }
 
@@ -143,7 +133,7 @@
     public void onCreate() {
         super.onCreate();
 
-        if (DEBUG) Log.i(LOG_TAG, "onCreate()");
+        Log.i(LOG_TAG, "onCreate()");
 
         mBluetoothManager = getSystemService(BluetoothManager.class);
         mBluetoothAdapter = mBluetoothManager.getAdapter();
@@ -151,7 +141,6 @@
         mWifiManager = getSystemService(WifiManager.class);
 
         mDevicesFound = new ArrayList<>();
-        mDevicesAdapter = new DevicesAdapter();
 
         sInstance = this;
     }
@@ -165,10 +154,13 @@
             mWifiFilters = CollectionUtils.filter(mFilters, WifiDeviceFilter.class);
             mBluetoothFilters = CollectionUtils.filter(mFilters, BluetoothDeviceFilter.class);
             mBLEFilters = CollectionUtils.filter(mFilters, BluetoothLeDeviceFilter.class);
-            mBLEScanFilters = CollectionUtils.map(mBLEFilters, BluetoothLeDeviceFilter::getScanFilter);
+            mBLEScanFilters
+                    = CollectionUtils.map(mBLEFilters, BluetoothLeDeviceFilter::getScanFilter);
 
             reset();
-        } else if (DEBUG) Log.i(LOG_TAG, "startDiscovery: duplicate request: " + request);
+        } else {
+            Log.i(LOG_TAG, "startDiscovery: duplicate request: " + request);
+        }
 
         if (!ArrayUtils.isEmpty(mDevicesFound)) {
             onReadyToShowUI();
@@ -205,17 +197,20 @@
             final IntentFilter intentFilter = new IntentFilter();
             intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
 
+            Log.i(LOG_TAG, "registerReceiver(BluetoothDevice.ACTION_FOUND)");
             mBluetoothBroadcastReceiver = new BluetoothBroadcastReceiver();
             registerReceiver(mBluetoothBroadcastReceiver, intentFilter);
             mBluetoothAdapter.startDiscovery();
         }
 
         if (shouldScan(mBLEFilters) && mBLEScanner != null) {
+            Log.i(LOG_TAG, "BLEScanner.startScan");
             mBLEScanCallback = new BLEScanCallback();
             mBLEScanner.startScan(mBLEScanFilters, mDefaultScanSettings, mBLEScanCallback);
         }
 
         if (shouldScan(mWifiFilters)) {
+            Log.i(LOG_TAG, "registerReceiver(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)");
             mWifiBroadcastReceiver = new WifiBroadcastReceiver();
             registerReceiver(mWifiBroadcastReceiver,
                     new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
@@ -223,7 +218,7 @@
         }
         mIsScanning = true;
         Handler.getMain().sendMessageDelayed(
-                obtainMessage(DeviceDiscoveryService::stopScan, this),
+                obtainMessage(CompanionDeviceDiscoveryService::stopScan, this),
                 SCAN_TIMEOUT);
     }
 
@@ -233,26 +228,27 @@
 
     @MainThread
     private void reset() {
-        if (DEBUG) Log.i(LOG_TAG, "reset()");
+        Log.i(LOG_TAG, "reset()");
         stopScan();
         mDevicesFound.clear();
         mSelectedDevice = null;
-        mDevicesAdapter.notifyDataSetChanged();
+        CompanionDeviceActivity.notifyDevicesChanged();
     }
 
     @Override
     public boolean onUnbind(Intent intent) {
+        Log.i(LOG_TAG, "onUnbind(intent = " + intent + ")");
         stopScan();
         return super.onUnbind(intent);
     }
 
     private void stopScan() {
-        if (DEBUG) Log.i(LOG_TAG, "stopScan()");
+        Log.i(LOG_TAG, "stopScan()");
 
         if (!mIsScanning) return;
         mIsScanning = false;
 
-        DeviceChooserActivity activity = mActivity;
+        CompanionDeviceActivity activity = mActivity;
         if (activity != null) {
             if (activity.mDeviceListView != null) {
                 activity.mDeviceListView.removeFooterView(activity.mLoadingIndicator);
@@ -276,7 +272,7 @@
         if (device == null) return;
 
         Handler.getMain().sendMessage(obtainMessage(
-                DeviceDiscoveryService::onDeviceFoundMainThread, this, device));
+                CompanionDeviceDiscoveryService::onDeviceFoundMainThread, this, device));
     }
 
     @MainThread
@@ -292,7 +288,7 @@
             onReadyToShowUI();
         }
         mDevicesFound.add(device);
-        mDevicesAdapter.notifyDataSetChanged();
+        CompanionDeviceActivity.notifyDevicesChanged();
     }
 
     //TODO also, on timeout -> call onFailure
@@ -300,7 +296,7 @@
         try {
             mFindCallback.onSuccess(PendingIntent.getActivity(
                     this, 0,
-                    new Intent(this, DeviceChooserActivity.class),
+                    new Intent(this, CompanionDeviceActivity.class),
                     PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT
                             | PendingIntent.FLAG_IMMUTABLE));
         } catch (RemoteException e) {
@@ -311,13 +307,13 @@
     private void onDeviceLost(@Nullable DeviceFilterPair device) {
         Log.i(LOG_TAG, "Lost device " + device.getDisplayName());
         Handler.getMain().sendMessage(obtainMessage(
-                DeviceDiscoveryService::onDeviceLostMainThread, this, device));
+                CompanionDeviceDiscoveryService::onDeviceLostMainThread, this, device));
     }
 
     @MainThread
     void onDeviceLostMainThread(@Nullable DeviceFilterPair device) {
         mDevicesFound.remove(device);
-        mDevicesAdapter.notifyDataSetChanged();
+        CompanionDeviceActivity.notifyDevicesChanged();
     }
 
     void onDeviceSelected(String callingPackage, String deviceAddress) {
@@ -331,81 +327,6 @@
         mServiceCallback.cancel(true);
     }
 
-    class DevicesAdapter extends BaseAdapter {
-        private Drawable BLUETOOTH_ICON = icon(android.R.drawable.stat_sys_data_bluetooth);
-        private Drawable WIFI_ICON = icon(com.android.internal.R.drawable.ic_wifi_signal_3);
-
-        private SparseArray<Integer> mColors = new SparseArray();
-
-        private Drawable icon(int drawableRes) {
-            Drawable icon = getResources().getDrawable(drawableRes, null);
-            icon.setTint(Color.DKGRAY);
-            return icon;
-        }
-
-        @Override
-        public View getView(
-                int position,
-                @Nullable View convertView,
-                @NonNull ViewGroup parent) {
-            TextView view = convertView instanceof TextView
-                    ? (TextView) convertView
-                    : newView();
-            bind(view, getItem(position));
-            return view;
-        }
-
-        private void bind(TextView textView, DeviceFilterPair device) {
-            textView.setText(device.getDisplayName());
-            textView.setBackgroundColor(
-                    device.equals(mSelectedDevice)
-                            ? getColor(android.R.attr.colorControlHighlight)
-                            : Color.TRANSPARENT);
-            textView.setCompoundDrawablesWithIntrinsicBounds(
-                    device.device instanceof android.net.wifi.ScanResult
-                        ? WIFI_ICON
-                        : BLUETOOTH_ICON,
-                    null, null, null);
-            textView.getCompoundDrawables()[0].setTint(getColor(android.R.attr.colorForeground));
-        }
-
-        private TextView newView() {
-            final TextView textView = new TextView(DeviceDiscoveryService.this);
-            textView.setTextColor(getColor(android.R.attr.colorForeground));
-            final int padding = DeviceChooserActivity.getPadding(getResources());
-            textView.setPadding(padding, padding, padding, padding);
-            textView.setCompoundDrawablePadding(padding);
-            return textView;
-        }
-
-        private int getColor(int colorAttr) {
-            if (mColors.contains(colorAttr)) {
-                return mColors.get(colorAttr);
-            }
-            TypedValue typedValue = new TypedValue();
-            TypedArray a = obtainStyledAttributes(typedValue.data, new int[] { colorAttr });
-            int result = a.getColor(0, 0);
-            a.recycle();
-            mColors.put(colorAttr, result);
-            return result;
-        }
-
-        @Override
-        public int getCount() {
-            return mDevicesFound.size();
-        }
-
-        @Override
-        public DeviceFilterPair getItem(int position) {
-            return mDevicesFound.get(position);
-        }
-
-        @Override
-        public long getItemId(int position) {
-            return position;
-        }
-    }
-
     /**
      * A pair of device and a filter that matched this device if any.
      *
diff --git a/packages/Connectivity/framework/Android.bp b/packages/Connectivity/framework/Android.bp
index c7e261c..86b85e83 100644
--- a/packages/Connectivity/framework/Android.bp
+++ b/packages/Connectivity/framework/Android.bp
@@ -58,3 +58,28 @@
         "//packages/modules/Connectivity:__subpackages__",
     ],
 }
+
+java_sdk_library {
+    name: "framework-connectivity",
+    api_only: true,
+    defaults: ["framework-module-defaults"],
+    // TODO: build against module API
+    platform_apis: true,
+    srcs: [
+        ":framework-connectivity-sources",
+    ],
+    aidl: {
+        include_dirs: [
+            // Include directories for parcelables that are part of the stable API, and need a
+            // one-line "parcelable X" .aidl declaration to be used in AIDL interfaces.
+            // TODO(b/180293679): remove these dependencies as they should not be necessary once
+            // the module builds against API (the parcelable declarations exist in framework.aidl)
+            "frameworks/base/core/java", // For framework parcelables
+            "frameworks/native/aidl/binder", // For PersistableBundle.aidl
+        ],
+    },
+    libs: [
+        "unsupportedappusage",
+    ],
+    permitted_packages: ["android.net", "com.android.connectivity.aidl"],
+}
diff --git a/core/java/android/net/QosFilterParcelable.aidl b/packages/Connectivity/framework/aidl-export/android/net/QosFilterParcelable.aidl
similarity index 100%
rename from core/java/android/net/QosFilterParcelable.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/QosFilterParcelable.aidl
diff --git a/core/java/android/net/QosSession.aidl b/packages/Connectivity/framework/aidl-export/android/net/QosSession.aidl
similarity index 100%
rename from core/java/android/net/QosSession.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/QosSession.aidl
diff --git a/core/java/android/net/QosSocketInfo.aidl b/packages/Connectivity/framework/aidl-export/android/net/QosSocketInfo.aidl
similarity index 100%
rename from core/java/android/net/QosSocketInfo.aidl
rename to packages/Connectivity/framework/aidl-export/android/net/QosSocketInfo.aidl
diff --git a/packages/Connectivity/framework/api/current.txt b/packages/Connectivity/framework/api/current.txt
new file mode 100644
index 0000000..a8f1a4d
--- /dev/null
+++ b/packages/Connectivity/framework/api/current.txt
@@ -0,0 +1,460 @@
+// Signature format: 2.0
+package android.net {
+
+  public class CaptivePortal implements android.os.Parcelable {
+    method public int describeContents();
+    method public void ignoreNetwork();
+    method public void reportCaptivePortalDismissed();
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortal> CREATOR;
+  }
+
+  public class ConnectivityDiagnosticsManager {
+    method public void registerConnectivityDiagnosticsCallback(@NonNull android.net.NetworkRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback);
+    method public void unregisterConnectivityDiagnosticsCallback(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback);
+  }
+
+  public abstract static class ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback {
+    ctor public ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback();
+    method public void onConnectivityReportAvailable(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityReport);
+    method public void onDataStallSuspected(@NonNull android.net.ConnectivityDiagnosticsManager.DataStallReport);
+    method public void onNetworkConnectivityReported(@NonNull android.net.Network, boolean);
+  }
+
+  public static final class ConnectivityDiagnosticsManager.ConnectivityReport implements android.os.Parcelable {
+    ctor public ConnectivityDiagnosticsManager.ConnectivityReport(@NonNull android.net.Network, long, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkCapabilities, @NonNull android.os.PersistableBundle);
+    method public int describeContents();
+    method @NonNull public android.os.PersistableBundle getAdditionalInfo();
+    method @NonNull public android.net.LinkProperties getLinkProperties();
+    method @NonNull public android.net.Network getNetwork();
+    method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities();
+    method public long getReportTimestamp();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.ConnectivityDiagnosticsManager.ConnectivityReport> CREATOR;
+    field public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK = "networkProbesAttempted";
+    field public static final String KEY_NETWORK_PROBES_SUCCEEDED_BITMASK = "networkProbesSucceeded";
+    field public static final String KEY_NETWORK_VALIDATION_RESULT = "networkValidationResult";
+    field public static final int NETWORK_PROBE_DNS = 4; // 0x4
+    field public static final int NETWORK_PROBE_FALLBACK = 32; // 0x20
+    field public static final int NETWORK_PROBE_HTTP = 8; // 0x8
+    field public static final int NETWORK_PROBE_HTTPS = 16; // 0x10
+    field public static final int NETWORK_PROBE_PRIVATE_DNS = 64; // 0x40
+    field public static final int NETWORK_VALIDATION_RESULT_INVALID = 0; // 0x0
+    field public static final int NETWORK_VALIDATION_RESULT_PARTIALLY_VALID = 2; // 0x2
+    field public static final int NETWORK_VALIDATION_RESULT_SKIPPED = 3; // 0x3
+    field public static final int NETWORK_VALIDATION_RESULT_VALID = 1; // 0x1
+  }
+
+  public static final class ConnectivityDiagnosticsManager.DataStallReport implements android.os.Parcelable {
+    ctor public ConnectivityDiagnosticsManager.DataStallReport(@NonNull android.net.Network, long, int, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkCapabilities, @NonNull android.os.PersistableBundle);
+    method public int describeContents();
+    method public int getDetectionMethod();
+    method @NonNull public android.net.LinkProperties getLinkProperties();
+    method @NonNull public android.net.Network getNetwork();
+    method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities();
+    method public long getReportTimestamp();
+    method @NonNull public android.os.PersistableBundle getStallDetails();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.ConnectivityDiagnosticsManager.DataStallReport> CREATOR;
+    field public static final int DETECTION_METHOD_DNS_EVENTS = 1; // 0x1
+    field public static final int DETECTION_METHOD_TCP_METRICS = 2; // 0x2
+    field public static final String KEY_DNS_CONSECUTIVE_TIMEOUTS = "dnsConsecutiveTimeouts";
+    field public static final String KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS = "tcpMetricsCollectionPeriodMillis";
+    field public static final String KEY_TCP_PACKET_FAIL_RATE = "tcpPacketFailRate";
+  }
+
+  public class ConnectivityManager {
+    method public void addDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
+    method public boolean bindProcessToNetwork(@Nullable android.net.Network);
+    method @NonNull public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull android.net.IpSecManager.UdpEncapsulationSocket, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
+    method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network getActiveNetwork();
+    method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getActiveNetworkInfo();
+    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo[] getAllNetworkInfo();
+    method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network[] getAllNetworks();
+    method @Deprecated public boolean getBackgroundDataSetting();
+    method @Nullable public android.net.Network getBoundNetworkForProcess();
+    method public int getConnectionOwnerUid(int, @NonNull java.net.InetSocketAddress, @NonNull java.net.InetSocketAddress);
+    method @Nullable public android.net.ProxyInfo getDefaultProxy();
+    method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.LinkProperties getLinkProperties(@Nullable android.net.Network);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public int getMultipathPreference(@Nullable android.net.Network);
+    method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkCapabilities getNetworkCapabilities(@Nullable android.net.Network);
+    method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getNetworkInfo(int);
+    method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getNetworkInfo(@Nullable android.net.Network);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public int getNetworkPreference();
+    method @Nullable public byte[] getNetworkWatchlistConfigHash();
+    method @Deprecated @Nullable public static android.net.Network getProcessDefaultNetwork();
+    method public int getRestrictBackgroundStatus();
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public boolean isActiveNetworkMetered();
+    method public boolean isDefaultNetworkActive();
+    method @Deprecated public static boolean isNetworkTypeValid(int);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.app.PendingIntent);
+    method public void releaseNetworkRequest(@NonNull android.app.PendingIntent);
+    method public void removeDefaultNetworkActiveListener(@NonNull android.net.ConnectivityManager.OnNetworkActiveListener);
+    method @Deprecated public void reportBadNetwork(@Nullable android.net.Network);
+    method public void reportNetworkConnectivity(@Nullable android.net.Network, boolean);
+    method public boolean requestBandwidthUpdate(@NonNull android.net.Network);
+    method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback);
+    method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
+    method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, int);
+    method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler, int);
+    method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.app.PendingIntent);
+    method @Deprecated public void setNetworkPreference(int);
+    method @Deprecated public static boolean setProcessDefaultNetwork(@Nullable android.net.Network);
+    method public void unregisterNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback);
+    method public void unregisterNetworkCallback(@NonNull android.app.PendingIntent);
+    field @Deprecated public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
+    field public static final String ACTION_CAPTIVE_PORTAL_SIGN_IN = "android.net.conn.CAPTIVE_PORTAL";
+    field public static final String ACTION_RESTRICT_BACKGROUND_CHANGED = "android.net.conn.RESTRICT_BACKGROUND_CHANGED";
+    field @Deprecated public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
+    field @Deprecated public static final int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
+    field public static final String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL";
+    field public static final String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL";
+    field @Deprecated public static final String EXTRA_EXTRA_INFO = "extraInfo";
+    field @Deprecated public static final String EXTRA_IS_FAILOVER = "isFailover";
+    field public static final String EXTRA_NETWORK = "android.net.extra.NETWORK";
+    field @Deprecated public static final String EXTRA_NETWORK_INFO = "networkInfo";
+    field public static final String EXTRA_NETWORK_REQUEST = "android.net.extra.NETWORK_REQUEST";
+    field @Deprecated public static final String EXTRA_NETWORK_TYPE = "networkType";
+    field public static final String EXTRA_NO_CONNECTIVITY = "noConnectivity";
+    field @Deprecated public static final String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
+    field public static final String EXTRA_REASON = "reason";
+    field public static final int MULTIPATH_PREFERENCE_HANDOVER = 1; // 0x1
+    field public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 4; // 0x4
+    field public static final int MULTIPATH_PREFERENCE_RELIABILITY = 2; // 0x2
+    field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
+    field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
+    field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
+    field @Deprecated public static final int TYPE_BLUETOOTH = 7; // 0x7
+    field @Deprecated public static final int TYPE_DUMMY = 8; // 0x8
+    field @Deprecated public static final int TYPE_ETHERNET = 9; // 0x9
+    field @Deprecated public static final int TYPE_MOBILE = 0; // 0x0
+    field @Deprecated public static final int TYPE_MOBILE_DUN = 4; // 0x4
+    field @Deprecated public static final int TYPE_MOBILE_HIPRI = 5; // 0x5
+    field @Deprecated public static final int TYPE_MOBILE_MMS = 2; // 0x2
+    field @Deprecated public static final int TYPE_MOBILE_SUPL = 3; // 0x3
+    field @Deprecated public static final int TYPE_VPN = 17; // 0x11
+    field @Deprecated public static final int TYPE_WIFI = 1; // 0x1
+    field @Deprecated public static final int TYPE_WIMAX = 6; // 0x6
+  }
+
+  public static class ConnectivityManager.NetworkCallback {
+    ctor public ConnectivityManager.NetworkCallback();
+    method public void onAvailable(@NonNull android.net.Network);
+    method public void onBlockedStatusChanged(@NonNull android.net.Network, boolean);
+    method public void onCapabilitiesChanged(@NonNull android.net.Network, @NonNull android.net.NetworkCapabilities);
+    method public void onLinkPropertiesChanged(@NonNull android.net.Network, @NonNull android.net.LinkProperties);
+    method public void onLosing(@NonNull android.net.Network, int);
+    method public void onLost(@NonNull android.net.Network);
+    method public void onUnavailable();
+  }
+
+  public static interface ConnectivityManager.OnNetworkActiveListener {
+    method public void onNetworkActive();
+  }
+
+  public class DhcpInfo implements android.os.Parcelable {
+    ctor public DhcpInfo();
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.DhcpInfo> CREATOR;
+    field public int dns1;
+    field public int dns2;
+    field public int gateway;
+    field public int ipAddress;
+    field public int leaseDuration;
+    field public int netmask;
+    field public int serverAddress;
+  }
+
+  public final class DnsResolver {
+    method @NonNull public static android.net.DnsResolver getInstance();
+    method public void query(@Nullable android.net.Network, @NonNull String, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super java.util.List<java.net.InetAddress>>);
+    method public void query(@Nullable android.net.Network, @NonNull String, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super java.util.List<java.net.InetAddress>>);
+    method public void rawQuery(@Nullable android.net.Network, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super byte[]>);
+    method public void rawQuery(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super byte[]>);
+    field public static final int CLASS_IN = 1; // 0x1
+    field public static final int ERROR_PARSE = 0; // 0x0
+    field public static final int ERROR_SYSTEM = 1; // 0x1
+    field public static final int FLAG_EMPTY = 0; // 0x0
+    field public static final int FLAG_NO_CACHE_LOOKUP = 4; // 0x4
+    field public static final int FLAG_NO_CACHE_STORE = 2; // 0x2
+    field public static final int FLAG_NO_RETRY = 1; // 0x1
+    field public static final int TYPE_A = 1; // 0x1
+    field public static final int TYPE_AAAA = 28; // 0x1c
+  }
+
+  public static interface DnsResolver.Callback<T> {
+    method public void onAnswer(@NonNull T, int);
+    method public void onError(@NonNull android.net.DnsResolver.DnsException);
+  }
+
+  public static class DnsResolver.DnsException extends java.lang.Exception {
+    field public final int code;
+  }
+
+  public class InetAddresses {
+    method public static boolean isNumericAddress(@NonNull String);
+    method @NonNull public static java.net.InetAddress parseNumericAddress(@NonNull String);
+  }
+
+  public final class IpPrefix implements android.os.Parcelable {
+    method public boolean contains(@NonNull java.net.InetAddress);
+    method public int describeContents();
+    method @NonNull public java.net.InetAddress getAddress();
+    method @IntRange(from=0, to=128) public int getPrefixLength();
+    method @NonNull public byte[] getRawAddress();
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
+  }
+
+  public class LinkAddress implements android.os.Parcelable {
+    method public int describeContents();
+    method public java.net.InetAddress getAddress();
+    method public int getFlags();
+    method @IntRange(from=0, to=128) public int getPrefixLength();
+    method public int getScope();
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.LinkAddress> CREATOR;
+  }
+
+  public final class LinkProperties implements android.os.Parcelable {
+    ctor public LinkProperties();
+    method public boolean addRoute(@NonNull android.net.RouteInfo);
+    method public void clear();
+    method public int describeContents();
+    method @Nullable public java.net.Inet4Address getDhcpServerAddress();
+    method @NonNull public java.util.List<java.net.InetAddress> getDnsServers();
+    method @Nullable public String getDomains();
+    method @Nullable public android.net.ProxyInfo getHttpProxy();
+    method @Nullable public String getInterfaceName();
+    method @NonNull public java.util.List<android.net.LinkAddress> getLinkAddresses();
+    method public int getMtu();
+    method @Nullable public android.net.IpPrefix getNat64Prefix();
+    method @Nullable public String getPrivateDnsServerName();
+    method @NonNull public java.util.List<android.net.RouteInfo> getRoutes();
+    method public boolean isPrivateDnsActive();
+    method public boolean isWakeOnLanSupported();
+    method public void setDhcpServerAddress(@Nullable java.net.Inet4Address);
+    method public void setDnsServers(@NonNull java.util.Collection<java.net.InetAddress>);
+    method public void setDomains(@Nullable String);
+    method public void setHttpProxy(@Nullable android.net.ProxyInfo);
+    method public void setInterfaceName(@Nullable String);
+    method public void setLinkAddresses(@NonNull java.util.Collection<android.net.LinkAddress>);
+    method public void setMtu(int);
+    method public void setNat64Prefix(@Nullable android.net.IpPrefix);
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.LinkProperties> CREATOR;
+  }
+
+  public final class MacAddress implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public static android.net.MacAddress fromBytes(@NonNull byte[]);
+    method @NonNull public static android.net.MacAddress fromString(@NonNull String);
+    method public int getAddressType();
+    method @Nullable public java.net.Inet6Address getLinkLocalIpv6FromEui48Mac();
+    method public boolean isLocallyAssigned();
+    method public boolean matches(@NonNull android.net.MacAddress, @NonNull android.net.MacAddress);
+    method @NonNull public byte[] toByteArray();
+    method @NonNull public String toOuiString();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.net.MacAddress BROADCAST_ADDRESS;
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.MacAddress> CREATOR;
+    field public static final int TYPE_BROADCAST = 3; // 0x3
+    field public static final int TYPE_MULTICAST = 2; // 0x2
+    field public static final int TYPE_UNICAST = 1; // 0x1
+  }
+
+  public class Network implements android.os.Parcelable {
+    method public void bindSocket(java.net.DatagramSocket) throws java.io.IOException;
+    method public void bindSocket(java.net.Socket) throws java.io.IOException;
+    method public void bindSocket(java.io.FileDescriptor) throws java.io.IOException;
+    method public int describeContents();
+    method public static android.net.Network fromNetworkHandle(long);
+    method public java.net.InetAddress[] getAllByName(String) throws java.net.UnknownHostException;
+    method public java.net.InetAddress getByName(String) throws java.net.UnknownHostException;
+    method public long getNetworkHandle();
+    method public javax.net.SocketFactory getSocketFactory();
+    method public java.net.URLConnection openConnection(java.net.URL) throws java.io.IOException;
+    method public java.net.URLConnection openConnection(java.net.URL, java.net.Proxy) throws java.io.IOException;
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.Network> CREATOR;
+  }
+
+  public final class NetworkCapabilities implements android.os.Parcelable {
+    ctor public NetworkCapabilities();
+    ctor public NetworkCapabilities(android.net.NetworkCapabilities);
+    method public int describeContents();
+    method public int getLinkDownstreamBandwidthKbps();
+    method public int getLinkUpstreamBandwidthKbps();
+    method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
+    method public int getOwnerUid();
+    method public int getSignalStrength();
+    method @Nullable public android.net.TransportInfo getTransportInfo();
+    method public boolean hasCapability(int);
+    method public boolean hasTransport(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkCapabilities> CREATOR;
+    field public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17; // 0x11
+    field public static final int NET_CAPABILITY_CBS = 5; // 0x5
+    field public static final int NET_CAPABILITY_DUN = 2; // 0x2
+    field public static final int NET_CAPABILITY_EIMS = 10; // 0xa
+    field public static final int NET_CAPABILITY_ENTERPRISE = 29; // 0x1d
+    field public static final int NET_CAPABILITY_FOREGROUND = 19; // 0x13
+    field public static final int NET_CAPABILITY_FOTA = 3; // 0x3
+    field public static final int NET_CAPABILITY_IA = 7; // 0x7
+    field public static final int NET_CAPABILITY_IMS = 4; // 0x4
+    field public static final int NET_CAPABILITY_INTERNET = 12; // 0xc
+    field public static final int NET_CAPABILITY_MCX = 23; // 0x17
+    field public static final int NET_CAPABILITY_MMS = 0; // 0x0
+    field public static final int NET_CAPABILITY_NOT_CONGESTED = 20; // 0x14
+    field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
+    field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
+    field public static final int NET_CAPABILITY_NOT_ROAMING = 18; // 0x12
+    field public static final int NET_CAPABILITY_NOT_SUSPENDED = 21; // 0x15
+    field public static final int NET_CAPABILITY_NOT_VPN = 15; // 0xf
+    field public static final int NET_CAPABILITY_RCS = 8; // 0x8
+    field public static final int NET_CAPABILITY_SUPL = 1; // 0x1
+    field public static final int NET_CAPABILITY_TEMPORARILY_NOT_METERED = 25; // 0x19
+    field public static final int NET_CAPABILITY_TRUSTED = 14; // 0xe
+    field public static final int NET_CAPABILITY_VALIDATED = 16; // 0x10
+    field public static final int NET_CAPABILITY_WIFI_P2P = 6; // 0x6
+    field public static final int NET_CAPABILITY_XCAP = 9; // 0x9
+    field public static final int SIGNAL_STRENGTH_UNSPECIFIED = -2147483648; // 0x80000000
+    field public static final int TRANSPORT_BLUETOOTH = 2; // 0x2
+    field public static final int TRANSPORT_CELLULAR = 0; // 0x0
+    field public static final int TRANSPORT_ETHERNET = 3; // 0x3
+    field public static final int TRANSPORT_LOWPAN = 6; // 0x6
+    field public static final int TRANSPORT_VPN = 4; // 0x4
+    field public static final int TRANSPORT_WIFI = 1; // 0x1
+    field public static final int TRANSPORT_WIFI_AWARE = 5; // 0x5
+  }
+
+  @Deprecated public class NetworkInfo implements android.os.Parcelable {
+    ctor @Deprecated public NetworkInfo(int, int, @Nullable String, @Nullable String);
+    method @Deprecated public int describeContents();
+    method @Deprecated @NonNull public android.net.NetworkInfo.DetailedState getDetailedState();
+    method @Deprecated public String getExtraInfo();
+    method @Deprecated public String getReason();
+    method @Deprecated public android.net.NetworkInfo.State getState();
+    method @Deprecated public int getSubtype();
+    method @Deprecated public String getSubtypeName();
+    method @Deprecated public int getType();
+    method @Deprecated public String getTypeName();
+    method @Deprecated public boolean isAvailable();
+    method @Deprecated public boolean isConnected();
+    method @Deprecated public boolean isConnectedOrConnecting();
+    method @Deprecated public boolean isFailover();
+    method @Deprecated public boolean isRoaming();
+    method @Deprecated public void setDetailedState(@NonNull android.net.NetworkInfo.DetailedState, @Nullable String, @Nullable String);
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR;
+  }
+
+  @Deprecated public enum NetworkInfo.DetailedState {
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState AUTHENTICATING;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState BLOCKED;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CAPTIVE_PORTAL_CHECK;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CONNECTED;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CONNECTING;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState DISCONNECTED;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState DISCONNECTING;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState FAILED;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState IDLE;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState OBTAINING_IPADDR;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState SCANNING;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState SUSPENDED;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState VERIFYING_POOR_LINK;
+  }
+
+  @Deprecated public enum NetworkInfo.State {
+    enum_constant @Deprecated public static final android.net.NetworkInfo.State CONNECTED;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.State CONNECTING;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.State DISCONNECTED;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.State DISCONNECTING;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.State SUSPENDED;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.State UNKNOWN;
+  }
+
+  public class NetworkRequest implements android.os.Parcelable {
+    method public boolean canBeSatisfiedBy(@Nullable android.net.NetworkCapabilities);
+    method public int describeContents();
+    method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
+    method public boolean hasCapability(int);
+    method public boolean hasTransport(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkRequest> CREATOR;
+  }
+
+  public static class NetworkRequest.Builder {
+    ctor public NetworkRequest.Builder();
+    method public android.net.NetworkRequest.Builder addCapability(int);
+    method public android.net.NetworkRequest.Builder addTransportType(int);
+    method public android.net.NetworkRequest build();
+    method @NonNull public android.net.NetworkRequest.Builder clearCapabilities();
+    method public android.net.NetworkRequest.Builder removeCapability(int);
+    method public android.net.NetworkRequest.Builder removeTransportType(int);
+    method @Deprecated public android.net.NetworkRequest.Builder setNetworkSpecifier(String);
+    method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
+  }
+
+  public class ProxyInfo implements android.os.Parcelable {
+    ctor public ProxyInfo(@Nullable android.net.ProxyInfo);
+    method public static android.net.ProxyInfo buildDirectProxy(String, int);
+    method public static android.net.ProxyInfo buildDirectProxy(String, int, java.util.List<java.lang.String>);
+    method public static android.net.ProxyInfo buildPacProxy(android.net.Uri);
+    method @NonNull public static android.net.ProxyInfo buildPacProxy(@NonNull android.net.Uri, int);
+    method public int describeContents();
+    method public String[] getExclusionList();
+    method public String getHost();
+    method public android.net.Uri getPacFileUrl();
+    method public int getPort();
+    method public boolean isValid();
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.ProxyInfo> CREATOR;
+  }
+
+  public final class RouteInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.net.IpPrefix getDestination();
+    method @Nullable public java.net.InetAddress getGateway();
+    method @Nullable public String getInterface();
+    method public boolean hasGateway();
+    method public boolean isDefaultRoute();
+    method public boolean matches(java.net.InetAddress);
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.RouteInfo> CREATOR;
+  }
+
+  public abstract class SocketKeepalive implements java.lang.AutoCloseable {
+    method public final void close();
+    method public final void start(@IntRange(from=0xa, to=0xe10) int);
+    method public final void stop();
+    field public static final int ERROR_HARDWARE_ERROR = -31; // 0xffffffe1
+    field public static final int ERROR_INSUFFICIENT_RESOURCES = -32; // 0xffffffe0
+    field public static final int ERROR_INVALID_INTERVAL = -24; // 0xffffffe8
+    field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb
+    field public static final int ERROR_INVALID_LENGTH = -23; // 0xffffffe9
+    field public static final int ERROR_INVALID_NETWORK = -20; // 0xffffffec
+    field public static final int ERROR_INVALID_PORT = -22; // 0xffffffea
+    field public static final int ERROR_INVALID_SOCKET = -25; // 0xffffffe7
+    field public static final int ERROR_SOCKET_NOT_IDLE = -26; // 0xffffffe6
+    field public static final int ERROR_UNSUPPORTED = -30; // 0xffffffe2
+  }
+
+  public static class SocketKeepalive.Callback {
+    ctor public SocketKeepalive.Callback();
+    method public void onDataReceived();
+    method public void onError(int);
+    method public void onStarted();
+    method public void onStopped();
+  }
+
+  public interface TransportInfo {
+  }
+
+}
+
diff --git a/packages/Connectivity/framework/api/lint-baseline.txt b/packages/Connectivity/framework/api/lint-baseline.txt
new file mode 100644
index 0000000..2f4004a
--- /dev/null
+++ b/packages/Connectivity/framework/api/lint-baseline.txt
@@ -0,0 +1,4 @@
+// Baseline format: 1.0
+VisiblySynchronized: android.net.NetworkInfo#toString():
+    Internal locks must not be exposed (synchronizing on this or class is still
+    externally observable): method android.net.NetworkInfo.toString()
diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt
new file mode 100644
index 0000000..a9fd6f2
--- /dev/null
+++ b/packages/Connectivity/framework/api/module-lib-current.txt
@@ -0,0 +1,62 @@
+// Signature format: 2.0
+package android.net {
+
+  public final class ConnectivityFrameworkInitializer {
+    method public static void registerServiceWrappers();
+  }
+
+  public class ConnectivityManager {
+    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
+    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @Nullable android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
+  }
+
+  public final class NetworkAgentConfig implements android.os.Parcelable {
+    method @Nullable public String getSubscriberId();
+  }
+
+  public static final class NetworkAgentConfig.Builder {
+    method @NonNull public android.net.NetworkAgentConfig.Builder setSubscriberId(@Nullable String);
+  }
+
+  public final class NetworkCapabilities implements android.os.Parcelable {
+    field public static final int TRANSPORT_TEST = 7; // 0x7
+  }
+
+  public final class TcpRepairWindow {
+    ctor public TcpRepairWindow(int, int, int, int, int, int);
+    field public final int maxWindow;
+    field public final int rcvWnd;
+    field public final int rcvWndScale;
+    field public final int rcvWup;
+    field public final int sndWl1;
+    field public final int sndWnd;
+  }
+
+  public final class TestNetworkInterface implements android.os.Parcelable {
+    ctor public TestNetworkInterface(@NonNull android.os.ParcelFileDescriptor, @NonNull String);
+    method public int describeContents();
+    method @NonNull public android.os.ParcelFileDescriptor getFileDescriptor();
+    method @NonNull public String getInterfaceName();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.TestNetworkInterface> CREATOR;
+  }
+
+  public class TestNetworkManager {
+    method @NonNull public android.net.TestNetworkInterface createTapInterface();
+    method @NonNull public android.net.TestNetworkInterface createTunInterface(@NonNull java.util.Collection<android.net.LinkAddress>);
+    method public void setupTestNetwork(@NonNull String, @NonNull android.os.IBinder);
+    method public void teardownTestNetwork(@NonNull android.net.Network);
+    field public static final String TEST_TAP_PREFIX = "testtap";
+  }
+
+  public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo {
+    ctor public VpnTransportInfo(int);
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.VpnTransportInfo> CREATOR;
+    field public final int type;
+  }
+
+}
+
diff --git a/packages/Connectivity/framework/api/module-lib-removed.txt b/packages/Connectivity/framework/api/module-lib-removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/packages/Connectivity/framework/api/module-lib-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/packages/Connectivity/framework/api/removed.txt b/packages/Connectivity/framework/api/removed.txt
new file mode 100644
index 0000000..303a1e61
--- /dev/null
+++ b/packages/Connectivity/framework/api/removed.txt
@@ -0,0 +1,11 @@
+// Signature format: 2.0
+package android.net {
+
+  public class ConnectivityManager {
+    method @Deprecated public boolean requestRouteToHost(int, int);
+    method @Deprecated public int startUsingNetworkFeature(int, String);
+    method @Deprecated public int stopUsingNetworkFeature(int, String);
+  }
+
+}
+
diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt
new file mode 100644
index 0000000..373fa3c
--- /dev/null
+++ b/packages/Connectivity/framework/api/system-current.txt
@@ -0,0 +1,444 @@
+// Signature format: 2.0
+package android.net {
+
+  public class CaptivePortal implements android.os.Parcelable {
+    method public void logEvent(int, @NonNull String);
+    method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void reevaluateNetwork();
+    method public void useNetwork();
+    field public static final int APP_REQUEST_REEVALUATION_REQUIRED = 100; // 0x64
+    field public static final int APP_RETURN_DISMISSED = 0; // 0x0
+    field public static final int APP_RETURN_UNWANTED = 1; // 0x1
+    field public static final int APP_RETURN_WANTED_AS_IS = 2; // 0x2
+  }
+
+  public final class CaptivePortalData implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getByteLimit();
+    method public long getExpiryTimeMillis();
+    method public long getRefreshTimeMillis();
+    method @Nullable public android.net.Uri getUserPortalUrl();
+    method public int getUserPortalUrlSource();
+    method @Nullable public String getVenueFriendlyName();
+    method @Nullable public android.net.Uri getVenueInfoUrl();
+    method public int getVenueInfoUrlSource();
+    method public boolean isCaptive();
+    method public boolean isSessionExtendable();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int CAPTIVE_PORTAL_DATA_SOURCE_OTHER = 0; // 0x0
+    field public static final int CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT = 1; // 0x1
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortalData> CREATOR;
+  }
+
+  public static class CaptivePortalData.Builder {
+    ctor public CaptivePortalData.Builder();
+    ctor public CaptivePortalData.Builder(@Nullable android.net.CaptivePortalData);
+    method @NonNull public android.net.CaptivePortalData build();
+    method @NonNull public android.net.CaptivePortalData.Builder setBytesRemaining(long);
+    method @NonNull public android.net.CaptivePortalData.Builder setCaptive(boolean);
+    method @NonNull public android.net.CaptivePortalData.Builder setExpiryTime(long);
+    method @NonNull public android.net.CaptivePortalData.Builder setRefreshTime(long);
+    method @NonNull public android.net.CaptivePortalData.Builder setSessionExtendable(boolean);
+    method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri);
+    method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri, int);
+    method @NonNull public android.net.CaptivePortalData.Builder setVenueFriendlyName(@Nullable String);
+    method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri);
+    method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri, int);
+  }
+
+  public class ConnectivityManager {
+    method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createNattKeepalive(@NonNull android.net.Network, @NonNull android.os.ParcelFileDescriptor, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
+    method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull java.net.Socket, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String getCaptivePortalServerUrl();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
+    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public int registerNetworkProvider(@NonNull android.net.NetworkProvider);
+    method public void registerQosCallback(@NonNull android.net.QosSocketInfo, @NonNull android.net.QosCallback, @NonNull java.util.concurrent.Executor);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
+    method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void requestNetwork(@NonNull android.net.NetworkRequest, int, int, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
+    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_AIRPLANE_MODE, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean);
+    method @RequiresPermission(android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE) public void setOemNetworkPreference(@NonNull android.net.OemNetworkPreferences, @Nullable java.util.concurrent.Executor, @Nullable android.net.ConnectivityManager.OnSetOemNetworkPreferenceListener);
+    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public boolean shouldAvoidBadWifi();
+    method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
+    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public void unregisterNetworkProvider(@NonNull android.net.NetworkProvider);
+    method public void unregisterQosCallback(@NonNull android.net.QosCallback);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
+    field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
+    field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
+    field public static final int TETHERING_BLUETOOTH = 2; // 0x2
+    field public static final int TETHERING_USB = 1; // 0x1
+    field public static final int TETHERING_WIFI = 0; // 0x0
+    field @Deprecated public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13; // 0xd
+    field @Deprecated public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
+    field @Deprecated public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
+    field public static final int TYPE_NONE = -1; // 0xffffffff
+    field @Deprecated public static final int TYPE_PROXY = 16; // 0x10
+    field @Deprecated public static final int TYPE_WIFI_P2P = 13; // 0xd
+  }
+
+  public static interface ConnectivityManager.OnSetOemNetworkPreferenceListener {
+    method public void onComplete();
+  }
+
+  @Deprecated public abstract static class ConnectivityManager.OnStartTetheringCallback {
+    ctor @Deprecated public ConnectivityManager.OnStartTetheringCallback();
+    method @Deprecated public void onTetheringFailed();
+    method @Deprecated public void onTetheringStarted();
+  }
+
+  @Deprecated public static interface ConnectivityManager.OnTetheringEntitlementResultListener {
+    method @Deprecated public void onTetheringEntitlementResult(int);
+  }
+
+  @Deprecated public abstract static class ConnectivityManager.OnTetheringEventCallback {
+    ctor @Deprecated public ConnectivityManager.OnTetheringEventCallback();
+    method @Deprecated public void onUpstreamChanged(@Nullable android.net.Network);
+  }
+
+  public final class InvalidPacketException extends java.lang.Exception {
+    ctor public InvalidPacketException(int);
+    method public int getError();
+    field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb
+    field public static final int ERROR_INVALID_LENGTH = -23; // 0xffffffe9
+    field public static final int ERROR_INVALID_PORT = -22; // 0xffffffea
+  }
+
+  public final class IpConfiguration implements android.os.Parcelable {
+    ctor public IpConfiguration();
+    ctor public IpConfiguration(@NonNull android.net.IpConfiguration);
+    method public int describeContents();
+    method @Nullable public android.net.ProxyInfo getHttpProxy();
+    method @NonNull public android.net.IpConfiguration.IpAssignment getIpAssignment();
+    method @NonNull public android.net.IpConfiguration.ProxySettings getProxySettings();
+    method @Nullable public android.net.StaticIpConfiguration getStaticIpConfiguration();
+    method public void setHttpProxy(@Nullable android.net.ProxyInfo);
+    method public void setIpAssignment(@NonNull android.net.IpConfiguration.IpAssignment);
+    method public void setProxySettings(@NonNull android.net.IpConfiguration.ProxySettings);
+    method public void setStaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.IpConfiguration> CREATOR;
+  }
+
+  public enum IpConfiguration.IpAssignment {
+    enum_constant public static final android.net.IpConfiguration.IpAssignment DHCP;
+    enum_constant public static final android.net.IpConfiguration.IpAssignment STATIC;
+    enum_constant public static final android.net.IpConfiguration.IpAssignment UNASSIGNED;
+  }
+
+  public enum IpConfiguration.ProxySettings {
+    enum_constant public static final android.net.IpConfiguration.ProxySettings NONE;
+    enum_constant public static final android.net.IpConfiguration.ProxySettings PAC;
+    enum_constant public static final android.net.IpConfiguration.ProxySettings STATIC;
+    enum_constant public static final android.net.IpConfiguration.ProxySettings UNASSIGNED;
+  }
+
+  public final class IpPrefix implements android.os.Parcelable {
+    ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
+    ctor public IpPrefix(@NonNull String);
+  }
+
+  public class KeepalivePacketData {
+    ctor protected KeepalivePacketData(@NonNull java.net.InetAddress, @IntRange(from=0, to=65535) int, @NonNull java.net.InetAddress, @IntRange(from=0, to=65535) int, @NonNull byte[]) throws android.net.InvalidPacketException;
+    method @NonNull public java.net.InetAddress getDstAddress();
+    method public int getDstPort();
+    method @NonNull public byte[] getPacket();
+    method @NonNull public java.net.InetAddress getSrcAddress();
+    method public int getSrcPort();
+  }
+
+  public class LinkAddress implements android.os.Parcelable {
+    ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int);
+    ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int, long, long);
+    ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
+    ctor public LinkAddress(@NonNull String);
+    ctor public LinkAddress(@NonNull String, int, int);
+    method public long getDeprecationTime();
+    method public long getExpirationTime();
+    method public boolean isGlobalPreferred();
+    method public boolean isIpv4();
+    method public boolean isIpv6();
+    method public boolean isSameAddressAs(@Nullable android.net.LinkAddress);
+    field public static final long LIFETIME_PERMANENT = 9223372036854775807L; // 0x7fffffffffffffffL
+    field public static final long LIFETIME_UNKNOWN = -1L; // 0xffffffffffffffffL
+  }
+
+  public final class LinkProperties implements android.os.Parcelable {
+    ctor public LinkProperties(@Nullable android.net.LinkProperties);
+    ctor public LinkProperties(@Nullable android.net.LinkProperties, boolean);
+    method public boolean addDnsServer(@NonNull java.net.InetAddress);
+    method public boolean addLinkAddress(@NonNull android.net.LinkAddress);
+    method public boolean addPcscfServer(@NonNull java.net.InetAddress);
+    method @NonNull public java.util.List<java.net.InetAddress> getAddresses();
+    method @NonNull public java.util.List<java.lang.String> getAllInterfaceNames();
+    method @NonNull public java.util.List<android.net.LinkAddress> getAllLinkAddresses();
+    method @NonNull public java.util.List<android.net.RouteInfo> getAllRoutes();
+    method @Nullable public android.net.Uri getCaptivePortalApiUrl();
+    method @Nullable public android.net.CaptivePortalData getCaptivePortalData();
+    method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers();
+    method @Nullable public String getTcpBufferSizes();
+    method @NonNull public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
+    method public boolean hasGlobalIpv6Address();
+    method public boolean hasIpv4Address();
+    method public boolean hasIpv4DefaultRoute();
+    method public boolean hasIpv4DnsServer();
+    method public boolean hasIpv6DefaultRoute();
+    method public boolean hasIpv6DnsServer();
+    method public boolean isIpv4Provisioned();
+    method public boolean isIpv6Provisioned();
+    method public boolean isProvisioned();
+    method public boolean isReachable(@NonNull java.net.InetAddress);
+    method public boolean removeDnsServer(@NonNull java.net.InetAddress);
+    method public boolean removeLinkAddress(@NonNull android.net.LinkAddress);
+    method public boolean removeRoute(@NonNull android.net.RouteInfo);
+    method public void setCaptivePortalApiUrl(@Nullable android.net.Uri);
+    method public void setCaptivePortalData(@Nullable android.net.CaptivePortalData);
+    method public void setPcscfServers(@NonNull java.util.Collection<java.net.InetAddress>);
+    method public void setPrivateDnsServerName(@Nullable String);
+    method public void setTcpBufferSizes(@Nullable String);
+    method public void setUsePrivateDns(boolean);
+    method public void setValidatedPrivateDnsServers(@NonNull java.util.Collection<java.net.InetAddress>);
+  }
+
+  public final class NattKeepalivePacketData extends android.net.KeepalivePacketData implements android.os.Parcelable {
+    ctor public NattKeepalivePacketData(@NonNull java.net.InetAddress, int, @NonNull java.net.InetAddress, int, @NonNull byte[]) throws android.net.InvalidPacketException;
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.NattKeepalivePacketData> CREATOR;
+  }
+
+  public class Network implements android.os.Parcelable {
+    ctor public Network(@NonNull android.net.Network);
+    method public int getNetId();
+    method @NonNull public android.net.Network getPrivateDnsBypassingCopy();
+  }
+
+  public abstract class NetworkAgent {
+    ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, int, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
+    method @Nullable public android.net.Network getNetwork();
+    method public void markConnected();
+    method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
+    method public void onAutomaticReconnectDisabled();
+    method public void onNetworkUnwanted();
+    method public void onQosCallbackRegistered(int, @NonNull android.net.QosFilter);
+    method public void onQosCallbackUnregistered(int);
+    method public void onRemoveKeepalivePacketFilter(int);
+    method public void onSaveAcceptUnvalidated(boolean);
+    method public void onSignalStrengthThresholdsUpdated(@NonNull int[]);
+    method public void onStartSocketKeepalive(int, @NonNull java.time.Duration, @NonNull android.net.KeepalivePacketData);
+    method public void onStopSocketKeepalive(int);
+    method public void onValidationStatus(int, @Nullable android.net.Uri);
+    method @NonNull public android.net.Network register();
+    method public final void sendLinkProperties(@NonNull android.net.LinkProperties);
+    method public final void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities);
+    method public final void sendNetworkScore(@IntRange(from=0, to=99) int);
+    method public final void sendQosCallbackError(int, int);
+    method public final void sendQosSessionAvailable(int, int, @NonNull android.telephony.data.EpsBearerQosSessionAttributes);
+    method public final void sendQosSessionLost(int, int);
+    method public final void sendSocketKeepaliveEvent(int, int);
+    method public final void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
+    method public void unregister();
+    field public static final int VALIDATION_STATUS_NOT_VALID = 2; // 0x2
+    field public static final int VALIDATION_STATUS_VALID = 1; // 0x1
+  }
+
+  public final class NetworkAgentConfig implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getLegacyType();
+    method @NonNull public String getLegacyTypeName();
+    method public boolean isExplicitlySelected();
+    method public boolean isPartialConnectivityAcceptable();
+    method public boolean isUnvalidatedConnectivityAcceptable();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkAgentConfig> CREATOR;
+  }
+
+  public static final class NetworkAgentConfig.Builder {
+    ctor public NetworkAgentConfig.Builder();
+    method @NonNull public android.net.NetworkAgentConfig build();
+    method @NonNull public android.net.NetworkAgentConfig.Builder setExplicitlySelected(boolean);
+    method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyType(int);
+    method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyTypeName(@NonNull String);
+    method @NonNull public android.net.NetworkAgentConfig.Builder setPartialConnectivityAcceptable(boolean);
+    method @NonNull public android.net.NetworkAgentConfig.Builder setUnvalidatedConnectivityAcceptable(boolean);
+  }
+
+  public final class NetworkCapabilities implements android.os.Parcelable {
+    ctor public NetworkCapabilities(@Nullable android.net.NetworkCapabilities, boolean);
+    method @NonNull public int[] getAdministratorUids();
+    method @Nullable public String getSsid();
+    method @NonNull public int[] getTransportTypes();
+    method public boolean isPrivateDnsBroken();
+    method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
+    field public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; // 0x1c
+    field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16
+    field public static final int NET_CAPABILITY_OEM_PRIVATE = 26; // 0x1a
+    field public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24; // 0x18
+    field public static final int NET_CAPABILITY_VEHICLE_INTERNAL = 27; // 0x1b
+  }
+
+  public static final class NetworkCapabilities.Builder {
+    ctor public NetworkCapabilities.Builder();
+    ctor public NetworkCapabilities.Builder(@NonNull android.net.NetworkCapabilities);
+    method @NonNull public android.net.NetworkCapabilities.Builder addCapability(int);
+    method @NonNull public android.net.NetworkCapabilities.Builder addTransportType(int);
+    method @NonNull public android.net.NetworkCapabilities build();
+    method @NonNull public android.net.NetworkCapabilities.Builder clearAll();
+    method @NonNull public android.net.NetworkCapabilities.Builder removeCapability(int);
+    method @NonNull public android.net.NetworkCapabilities.Builder removeTransportType(int);
+    method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAdministratorUids(@NonNull int[]);
+    method @NonNull public android.net.NetworkCapabilities.Builder setLinkDownstreamBandwidthKbps(int);
+    method @NonNull public android.net.NetworkCapabilities.Builder setLinkUpstreamBandwidthKbps(int);
+    method @NonNull public android.net.NetworkCapabilities.Builder setNetworkSpecifier(@Nullable android.net.NetworkSpecifier);
+    method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setOwnerUid(int);
+    method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorPackageName(@Nullable String);
+    method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorUid(int);
+    method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkCapabilities.Builder setSignalStrength(int);
+    method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setSsid(@Nullable String);
+    method @NonNull public android.net.NetworkCapabilities.Builder setTransportInfo(@Nullable android.net.TransportInfo);
+  }
+
+  public class NetworkProvider {
+    ctor public NetworkProvider(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String);
+    method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void declareNetworkRequestUnfulfillable(@NonNull android.net.NetworkRequest);
+    method public int getProviderId();
+    method public void onNetworkRequestWithdrawn(@NonNull android.net.NetworkRequest);
+    method public void onNetworkRequested(@NonNull android.net.NetworkRequest, @IntRange(from=0, to=99) int, int);
+    field public static final int ID_NONE = -1; // 0xffffffff
+  }
+
+  public class NetworkReleasedException extends java.lang.Exception {
+  }
+
+  public class NetworkRequest implements android.os.Parcelable {
+    method @Nullable public String getRequestorPackageName();
+    method public int getRequestorUid();
+  }
+
+  public static class NetworkRequest.Builder {
+    method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
+  }
+
+  public abstract class QosCallback {
+    ctor public QosCallback();
+    method public void onError(@NonNull android.net.QosCallbackException);
+    method public void onQosSessionAvailable(@NonNull android.net.QosSession, @NonNull android.net.QosSessionAttributes);
+    method public void onQosSessionLost(@NonNull android.net.QosSession);
+  }
+
+  public static class QosCallback.QosCallbackRegistrationException extends java.lang.RuntimeException {
+  }
+
+  public final class QosCallbackException extends java.lang.Exception {
+  }
+
+  public abstract class QosFilter {
+    method @NonNull public abstract android.net.Network getNetwork();
+    method public abstract boolean matchesLocalAddress(@NonNull java.net.InetAddress, int, int);
+  }
+
+  public final class QosSession implements android.os.Parcelable {
+    ctor public QosSession(int, int);
+    method public int describeContents();
+    method public int getSessionId();
+    method public int getSessionType();
+    method public long getUniqueId();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSession> CREATOR;
+    field public static final int TYPE_EPS_BEARER = 1; // 0x1
+  }
+
+  public interface QosSessionAttributes {
+  }
+
+  public final class QosSocketInfo implements android.os.Parcelable {
+    ctor public QosSocketInfo(@NonNull android.net.Network, @NonNull java.net.Socket) throws java.io.IOException;
+    method public int describeContents();
+    method @NonNull public java.net.InetSocketAddress getLocalSocketAddress();
+    method @NonNull public android.net.Network getNetwork();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSocketInfo> CREATOR;
+  }
+
+  public final class RouteInfo implements android.os.Parcelable {
+    ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int);
+    ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int, int);
+    method public int getMtu();
+    method public int getType();
+    field public static final int RTN_THROW = 9; // 0x9
+    field public static final int RTN_UNICAST = 1; // 0x1
+    field public static final int RTN_UNREACHABLE = 7; // 0x7
+  }
+
+  public abstract class SocketKeepalive implements java.lang.AutoCloseable {
+    field public static final int SUCCESS = 0; // 0x0
+  }
+
+  public class SocketLocalAddressChangedException extends java.lang.Exception {
+  }
+
+  public class SocketNotBoundException extends java.lang.Exception {
+  }
+
+  public final class StaticIpConfiguration implements android.os.Parcelable {
+    ctor public StaticIpConfiguration();
+    ctor public StaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
+    method public void addDnsServer(@NonNull java.net.InetAddress);
+    method public void clear();
+    method public int describeContents();
+    method @NonNull public java.util.List<java.net.InetAddress> getDnsServers();
+    method @Nullable public String getDomains();
+    method @Nullable public java.net.InetAddress getGateway();
+    method @Nullable public android.net.LinkAddress getIpAddress();
+    method @NonNull public java.util.List<android.net.RouteInfo> getRoutes(@Nullable String);
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.StaticIpConfiguration> CREATOR;
+  }
+
+  public static final class StaticIpConfiguration.Builder {
+    ctor public StaticIpConfiguration.Builder();
+    method @NonNull public android.net.StaticIpConfiguration build();
+    method @NonNull public android.net.StaticIpConfiguration.Builder setDnsServers(@NonNull Iterable<java.net.InetAddress>);
+    method @NonNull public android.net.StaticIpConfiguration.Builder setDomains(@Nullable String);
+    method @NonNull public android.net.StaticIpConfiguration.Builder setGateway(@Nullable java.net.InetAddress);
+    method @NonNull public android.net.StaticIpConfiguration.Builder setIpAddress(@Nullable android.net.LinkAddress);
+  }
+
+  public final class TcpKeepalivePacketData extends android.net.KeepalivePacketData implements android.os.Parcelable {
+    ctor public TcpKeepalivePacketData(@NonNull java.net.InetAddress, int, @NonNull java.net.InetAddress, int, @NonNull byte[], int, int, int, int, int, int) throws android.net.InvalidPacketException;
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.TcpKeepalivePacketData> CREATOR;
+    field public final int ipTos;
+    field public final int ipTtl;
+    field public final int tcpAck;
+    field public final int tcpSeq;
+    field public final int tcpWindow;
+    field public final int tcpWindowScale;
+  }
+
+  public interface TransportInfo {
+    method public default boolean hasLocationSensitiveFields();
+    method @NonNull public default android.net.TransportInfo makeCopy(boolean);
+  }
+
+}
+
+package android.net.apf {
+
+  public final class ApfCapabilities implements android.os.Parcelable {
+    ctor public ApfCapabilities(int, int, int);
+    method public int describeContents();
+    method public static boolean getApfDrop8023Frames();
+    method @NonNull public static int[] getApfEtherTypeBlackList();
+    method public boolean hasDataAccess();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.apf.ApfCapabilities> CREATOR;
+    field public final int apfPacketFormat;
+    field public final int apfVersionSupported;
+    field public final int maximumApfProgramSize;
+  }
+
+}
+
diff --git a/packages/Connectivity/framework/api/system-lint-baseline.txt b/packages/Connectivity/framework/api/system-lint-baseline.txt
new file mode 100644
index 0000000..9a97707
--- /dev/null
+++ b/packages/Connectivity/framework/api/system-lint-baseline.txt
@@ -0,0 +1 @@
+// Baseline format: 1.0
diff --git a/packages/Connectivity/framework/api/system-removed.txt b/packages/Connectivity/framework/api/system-removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/packages/Connectivity/framework/api/system-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index e7ab0a1..39ec2edc 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -2245,31 +2245,6 @@
         }
     }
 
-    /* TODO: These permissions checks don't belong in client-side code. Move them to
-     * services.jar, possibly in com.android.server.net. */
-
-    /** {@hide} */
-    public static final void enforceChangePermission(Context context,
-            String callingPkg, String callingAttributionTag) {
-        int uid = Binder.getCallingUid();
-        checkAndNoteChangeNetworkStateOperation(context, uid, callingPkg,
-                callingAttributionTag, true /* throwException */);
-    }
-
-    /**
-     * Check if the package is a allowed to change the network state. This also accounts that such
-     * an access happened.
-     *
-     * @return {@code true} iff the package is allowed to change the network state.
-     */
-    // TODO: Remove method and replace with direct call once R code is pushed to AOSP
-    private static boolean checkAndNoteChangeNetworkStateOperation(@NonNull Context context,
-            int uid, @NonNull String callingPackage, @Nullable String callingAttributionTag,
-            boolean throwException) {
-        return Settings.checkAndNoteChangeNetworkStateOperation(context, uid, callingPackage,
-                callingAttributionTag, throwException);
-    }
-
     /**
      * Check if the package is a allowed to write settings. This also accounts that such an access
      * happened.
diff --git a/core/java/android/net/IOnSetOemNetworkPreferenceListener.aidl b/packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
similarity index 100%
rename from core/java/android/net/IOnSetOemNetworkPreferenceListener.aidl
rename to packages/Connectivity/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
diff --git a/core/java/android/net/IQosCallback.aidl b/packages/Connectivity/framework/src/android/net/IQosCallback.aidl
similarity index 100%
rename from core/java/android/net/IQosCallback.aidl
rename to packages/Connectivity/framework/src/android/net/IQosCallback.aidl
diff --git a/core/java/android/net/NetworkReleasedException.java b/packages/Connectivity/framework/src/android/net/NetworkReleasedException.java
similarity index 100%
rename from core/java/android/net/NetworkReleasedException.java
rename to packages/Connectivity/framework/src/android/net/NetworkReleasedException.java
diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
index 4e3085f..b4a651c 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
@@ -16,6 +16,22 @@
 
 package android.net;
 
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -30,6 +46,8 @@
 import android.text.TextUtils;
 import android.util.proto.ProtoOutputStream;
 
+import java.util.Arrays;
+import java.util.List;
 import java.util.Objects;
 import java.util.Set;
 
@@ -154,8 +172,30 @@
      * needed in terms of {@link NetworkCapabilities} features
      */
     public static class Builder {
+        /**
+         * Capabilities that are currently compatible with VCN networks.
+         */
+        private static final List<Integer> VCN_SUPPORTED_CAPABILITIES = Arrays.asList(
+                NET_CAPABILITY_CAPTIVE_PORTAL,
+                NET_CAPABILITY_DUN,
+                NET_CAPABILITY_FOREGROUND,
+                NET_CAPABILITY_INTERNET,
+                NET_CAPABILITY_NOT_CONGESTED,
+                NET_CAPABILITY_NOT_METERED,
+                NET_CAPABILITY_NOT_RESTRICTED,
+                NET_CAPABILITY_NOT_ROAMING,
+                NET_CAPABILITY_NOT_SUSPENDED,
+                NET_CAPABILITY_NOT_VPN,
+                NET_CAPABILITY_PARTIAL_CONNECTIVITY,
+                NET_CAPABILITY_TEMPORARILY_NOT_METERED,
+                NET_CAPABILITY_TRUSTED,
+                NET_CAPABILITY_VALIDATED);
+
         private final NetworkCapabilities mNetworkCapabilities;
 
+        // A boolean that represents the user modified NOT_VCN_MANAGED capability.
+        private boolean mModifiedNotVcnManaged = false;
+
         /**
          * Default constructor for Builder.
          */
@@ -177,6 +217,7 @@
             // maybeMarkCapabilitiesRestricted() doesn't add back.
             final NetworkCapabilities nc = new NetworkCapabilities(mNetworkCapabilities);
             nc.maybeMarkCapabilitiesRestricted();
+            deduceNotVcnManagedCapability(nc);
             return new NetworkRequest(nc, ConnectivityManager.TYPE_NONE,
                     ConnectivityManager.REQUEST_ID_UNSET, Type.NONE);
         }
@@ -193,6 +234,9 @@
          */
         public Builder addCapability(@NetworkCapabilities.NetCapability int capability) {
             mNetworkCapabilities.addCapability(capability);
+            if (capability == NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) {
+                mModifiedNotVcnManaged = true;
+            }
             return this;
         }
 
@@ -204,6 +248,9 @@
          */
         public Builder removeCapability(@NetworkCapabilities.NetCapability int capability) {
             mNetworkCapabilities.removeCapability(capability);
+            if (capability == NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) {
+                mModifiedNotVcnManaged = true;
+            }
             return this;
         }
 
@@ -261,6 +308,9 @@
         @NonNull
         public Builder clearCapabilities() {
             mNetworkCapabilities.clearAll();
+            // If the caller explicitly clear all capabilities, the NOT_VCN_MANAGED capabilities
+            // should not be add back later.
+            mModifiedNotVcnManaged = true;
             return this;
         }
 
@@ -380,6 +430,25 @@
             mNetworkCapabilities.setSignalStrength(signalStrength);
             return this;
         }
+
+        /**
+         * Deduce the NET_CAPABILITY_NOT_VCN_MANAGED capability from other capabilities
+         * and user intention, which includes:
+         *   1. For the requests that don't have anything besides
+         *      {@link #VCN_SUPPORTED_CAPABILITIES}, add the NET_CAPABILITY_NOT_VCN_MANAGED to
+         *      allow the callers automatically utilize VCN networks if available.
+         *   2. For the requests that explicitly add or remove NET_CAPABILITY_NOT_VCN_MANAGED,
+         *      do not alter them to allow user fire request that suits their need.
+         *
+         * @hide
+         */
+        private void deduceNotVcnManagedCapability(final NetworkCapabilities nc) {
+            if (mModifiedNotVcnManaged) return;
+            for (final int cap : nc.getCapabilities()) {
+                if (!VCN_SUPPORTED_CAPABILITIES.contains(cap)) return;
+            }
+            nc.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
+        }
     }
 
     // implement the Parcelable interface
diff --git a/packages/Connectivity/framework/src/android/net/NetworkUtils.java b/packages/Connectivity/framework/src/android/net/NetworkUtils.java
index 9ccb04a..9e42bbe 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkUtils.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkUtils.java
@@ -87,21 +87,6 @@
     public static native int bindSocketToNetwork(FileDescriptor fd, int netId);
 
     /**
-     * Protect {@code fd} from VPN connections.  After protecting, data sent through
-     * this socket will go directly to the underlying network, so its traffic will not be
-     * forwarded through the VPN.
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public static native boolean protectFromVpn(FileDescriptor fd);
-
-    /**
-     * Protect {@code socketfd} from VPN connections.  After protecting, data sent through
-     * this socket will go directly to the underlying network, so its traffic will not be
-     * forwarded through the VPN.
-     */
-    public native static boolean protectFromVpn(int socketfd);
-
-    /**
      * Determine if {@code uid} can access network designated by {@code netId}.
      * @return {@code true} if {@code uid} can access network, {@code false} otherwise.
      */
diff --git a/core/java/android/net/QosCallback.java b/packages/Connectivity/framework/src/android/net/QosCallback.java
similarity index 100%
rename from core/java/android/net/QosCallback.java
rename to packages/Connectivity/framework/src/android/net/QosCallback.java
diff --git a/core/java/android/net/QosCallbackConnection.java b/packages/Connectivity/framework/src/android/net/QosCallbackConnection.java
similarity index 100%
rename from core/java/android/net/QosCallbackConnection.java
rename to packages/Connectivity/framework/src/android/net/QosCallbackConnection.java
diff --git a/core/java/android/net/QosCallbackException.java b/packages/Connectivity/framework/src/android/net/QosCallbackException.java
similarity index 100%
rename from core/java/android/net/QosCallbackException.java
rename to packages/Connectivity/framework/src/android/net/QosCallbackException.java
diff --git a/core/java/android/net/QosFilter.java b/packages/Connectivity/framework/src/android/net/QosFilter.java
similarity index 100%
rename from core/java/android/net/QosFilter.java
rename to packages/Connectivity/framework/src/android/net/QosFilter.java
diff --git a/core/java/android/net/QosFilterParcelable.java b/packages/Connectivity/framework/src/android/net/QosFilterParcelable.java
similarity index 100%
rename from core/java/android/net/QosFilterParcelable.java
rename to packages/Connectivity/framework/src/android/net/QosFilterParcelable.java
diff --git a/core/java/android/net/QosSession.java b/packages/Connectivity/framework/src/android/net/QosSession.java
similarity index 100%
rename from core/java/android/net/QosSession.java
rename to packages/Connectivity/framework/src/android/net/QosSession.java
diff --git a/core/java/android/net/QosSessionAttributes.java b/packages/Connectivity/framework/src/android/net/QosSessionAttributes.java
similarity index 100%
rename from core/java/android/net/QosSessionAttributes.java
rename to packages/Connectivity/framework/src/android/net/QosSessionAttributes.java
diff --git a/core/java/android/net/QosSocketFilter.java b/packages/Connectivity/framework/src/android/net/QosSocketFilter.java
similarity index 100%
rename from core/java/android/net/QosSocketFilter.java
rename to packages/Connectivity/framework/src/android/net/QosSocketFilter.java
diff --git a/core/java/android/net/QosSocketInfo.java b/packages/Connectivity/framework/src/android/net/QosSocketInfo.java
similarity index 100%
rename from core/java/android/net/QosSocketInfo.java
rename to packages/Connectivity/framework/src/android/net/QosSocketInfo.java
diff --git a/core/java/android/net/SocketLocalAddressChangedException.java b/packages/Connectivity/framework/src/android/net/SocketLocalAddressChangedException.java
similarity index 100%
rename from core/java/android/net/SocketLocalAddressChangedException.java
rename to packages/Connectivity/framework/src/android/net/SocketLocalAddressChangedException.java
diff --git a/core/java/android/net/SocketNotBoundException.java b/packages/Connectivity/framework/src/android/net/SocketNotBoundException.java
similarity index 100%
rename from core/java/android/net/SocketNotBoundException.java
rename to packages/Connectivity/framework/src/android/net/SocketNotBoundException.java
diff --git a/core/java/android/net/UidRange.aidl b/packages/Connectivity/framework/src/android/net/UidRange.aidl
similarity index 100%
rename from core/java/android/net/UidRange.aidl
rename to packages/Connectivity/framework/src/android/net/UidRange.aidl
diff --git a/core/java/android/net/UidRange.java b/packages/Connectivity/framework/src/android/net/UidRange.java
similarity index 86%
rename from core/java/android/net/UidRange.java
rename to packages/Connectivity/framework/src/android/net/UidRange.java
index f0e7da7..26518d3 100644
--- a/core/java/android/net/UidRange.java
+++ b/packages/Connectivity/framework/src/android/net/UidRange.java
@@ -16,8 +16,6 @@
 
 package android.net;
 
-import static android.os.UserHandle.PER_USER_RANGE;
-
 import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -52,14 +50,15 @@
 
     /** Returns the smallest user Id which is contained in this UidRange */
     public int getStartUser() {
-        return start / PER_USER_RANGE;
+        return UserHandle.getUserHandleForUid(start).getIdentifier();
     }
 
     /** Returns the largest user Id which is contained in this UidRange */
     public int getEndUser() {
-        return stop / PER_USER_RANGE;
+        return UserHandle.getUserHandleForUid(stop).getIdentifier();
     }
 
+    /** Returns whether the UidRange contains the specified UID. */
     public boolean contains(int uid) {
         return start <= uid && uid <= stop;
     }
@@ -72,7 +71,7 @@
     }
 
     /**
-     * @return {@code true} if this range contains every UID contained by the {@param other} range.
+     * @return {@code true} if this range contains every UID contained by the {@code other} range.
      */
     public boolean containsRange(UidRange other) {
         return start <= other.start && other.stop <= stop;
@@ -118,18 +117,18 @@
     }
 
     public static final @android.annotation.NonNull Creator<UidRange> CREATOR =
-        new Creator<UidRange>() {
-            @Override
-            public UidRange createFromParcel(Parcel in) {
-                int start = in.readInt();
-                int stop = in.readInt();
+            new Creator<UidRange>() {
+        @Override
+        public UidRange createFromParcel(Parcel in) {
+            int start = in.readInt();
+            int stop = in.readInt();
 
-                return new UidRange(start, stop);
-            }
-            @Override
-            public UidRange[] newArray(int size) {
-                return new UidRange[size];
-            }
+            return new UidRange(start, stop);
+        }
+        @Override
+        public UidRange[] newArray(int size) {
+            return new UidRange[size];
+        }
     };
 
     /**
diff --git a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
index 0242ba0..340141b 100644
--- a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
+++ b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 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.
diff --git a/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java b/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java
index 85e3fa3..43fffd7 100644
--- a/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java
+++ b/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java
@@ -40,6 +40,8 @@
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
 
 /**
  * A class to encapsulate management of the "Smart Networking" capability of
@@ -73,6 +75,32 @@
     private volatile int mMeteredMultipathPreference;
     private int mActiveSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
+    // Mainline module can't use internal HandlerExecutor, so add an identical executor here.
+    private static class HandlerExecutor implements Executor {
+        @NonNull
+        private final Handler mHandler;
+
+        HandlerExecutor(@NonNull Handler handler) {
+            mHandler = handler;
+        }
+        @Override
+        public void execute(Runnable command) {
+            if (!mHandler.post(command)) {
+                throw new RejectedExecutionException(mHandler + " is shutting down");
+            }
+        }
+    }
+
+    @VisibleForTesting
+    protected class ActiveDataSubscriptionIdChangedListener extends PhoneStateListener
+            implements PhoneStateListener.ActiveDataSubscriptionIdChangedListener {
+        @Override
+        public void onActiveDataSubscriptionIdChanged(int subId) {
+            mActiveSubId = subId;
+            reevaluateInternal();
+        }
+    }
+
     public MultinetworkPolicyTracker(Context ctx, Handler handler) {
         this(ctx, handler, null);
     }
@@ -93,14 +121,8 @@
             }
         };
 
-        ctx.getSystemService(TelephonyManager.class).listen(
-                new PhoneStateListener(handler.getLooper()) {
-            @Override
-            public void onActiveDataSubscriptionIdChanged(int subId) {
-                mActiveSubId = subId;
-                reevaluateInternal();
-            }
-        }, PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
+        ctx.getSystemService(TelephonyManager.class).registerPhoneStateListener(
+                new HandlerExecutor(handler), new ActiveDataSubscriptionIdChangedListener());
 
         updateAvoidBadWifi();
         updateMeteredMultipathPreference();
diff --git a/packages/Connectivity/service/Android.bp b/packages/Connectivity/service/Android.bp
index f20b89f..e65b7b4 100644
--- a/packages/Connectivity/service/Android.bp
+++ b/packages/Connectivity/service/Android.bp
@@ -63,6 +63,7 @@
         "unsupportedappusage",
     ],
     static_libs: [
+        "modules-utils-os",
         "net-utils-device-common",
         "net-utils-framework-common",
         "netd-client",
diff --git a/packages/Connectivity/service/jarjar-rules.txt b/packages/Connectivity/service/jarjar-rules.txt
index ef53ebb..d8205bf 100644
--- a/packages/Connectivity/service/jarjar-rules.txt
+++ b/packages/Connectivity/service/jarjar-rules.txt
@@ -1 +1,2 @@
-rule com.android.net.module.util.** com.android.connectivity.util.@1
\ No newline at end of file
+rule com.android.net.module.util.** com.android.connectivity.net-utils.@1
+rule com.android.modules.utils.** com.android.connectivity.modules-utils.@1
\ No newline at end of file
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index 7f19662..c1dca5d 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -394,16 +394,20 @@
     }
 
     private void executeNotifyIfInUseCommand() {
-        int status = getStatus();
-
-        if (status == STATUS_IN_USE) {
-            startForeground(NOTIFICATION_ID,
-                    buildNotification(STATUS_IN_USE, CAUSE_NOT_SPECIFIED));
-        } else if (status == STATUS_READY) {
-            startForeground(NOTIFICATION_ID,
-                    buildNotification(STATUS_READY, CAUSE_NOT_SPECIFIED));
-        } else {
-            stopSelf();
+        switch (getStatus()) {
+            case STATUS_IN_USE:
+                startForeground(NOTIFICATION_ID,
+                        buildNotification(STATUS_IN_USE, CAUSE_NOT_SPECIFIED));
+                break;
+            case STATUS_READY:
+                startForeground(NOTIFICATION_ID,
+                        buildNotification(STATUS_READY, CAUSE_NOT_SPECIFIED));
+                break;
+            case STATUS_IN_PROGRESS:
+                break;
+            case STATUS_NOT_STARTED:
+            default:
+                stopSelf();
         }
     }
 
diff --git a/packages/InputDevices/res/values-eu/strings.xml b/packages/InputDevices/res/values-eu/strings.xml
index 0346d74..513eba2 100644
--- a/packages/InputDevices/res/values-eu/strings.xml
+++ b/packages/InputDevices/res/values-eu/strings.xml
@@ -42,7 +42,7 @@
     <string name="keyboard_layout_greek" msgid="7289253560162386040">"Greziarra"</string>
     <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebrearra"</string>
     <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituaniera"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espainiera (Latinoamerika)"</string>
+    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espainiarra (Latinoamerika)"</string>
     <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letoniera"</string>
     <string name="keyboard_layout_persian" msgid="3920643161015888527">"Persiarra"</string>
     <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerbaijandarra"</string>
diff --git a/packages/LocalTransport/OWNERS b/packages/LocalTransport/OWNERS
new file mode 100644
index 0000000..d99779e
--- /dev/null
+++ b/packages/LocalTransport/OWNERS
@@ -0,0 +1 @@
+include /services/backup/OWNERS
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
index c9d8a81..139c8e5 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
@@ -162,6 +162,9 @@
         if (mParameters.isFakeEncryptionFlag()) {
             flags |= BackupAgent.FLAG_FAKE_CLIENT_SIDE_ENCRYPTION_ENABLED;
         }
+        if (mParameters.isDeviceTransfer()) {
+            flags |= BackupAgent.FLAG_DEVICE_TO_DEVICE_TRANSFER;
+        }
         return flags;
     }
 
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
index 8b4db92..2946db3 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
@@ -27,9 +27,11 @@
     private static final String SETTING = Settings.Secure.BACKUP_LOCAL_TRANSPORT_PARAMETERS;
     private static final String KEY_FAKE_ENCRYPTION_FLAG = "fake_encryption_flag";
     private static final String KEY_NON_INCREMENTAL_ONLY = "non_incremental_only";
+    private static final String KEY_IS_DEVICE_TRANSFER = "is_device_transfer";
 
     private boolean mFakeEncryptionFlag;
     private boolean mIsNonIncrementalOnly;
+    private boolean mIsDeviceTransfer;
 
     public LocalTransportParameters(Handler handler, ContentResolver resolver) {
         super(handler, resolver, Settings.Secure.getUriFor(SETTING));
@@ -43,6 +45,10 @@
         return mIsNonIncrementalOnly;
     }
 
+    boolean isDeviceTransfer() {
+        return mIsDeviceTransfer;
+    }
+
     public String getSettingValue(ContentResolver resolver) {
         return Settings.Secure.getString(resolver, SETTING);
     }
@@ -50,5 +56,6 @@
     public void update(KeyValueListParser parser) {
         mFakeEncryptionFlag = parser.getBoolean(KEY_FAKE_ENCRYPTION_FLAG, false);
         mIsNonIncrementalOnly = parser.getBoolean(KEY_NON_INCREMENTAL_ONLY, false);
+        mIsDeviceTransfer = parser.getBoolean(KEY_IS_DEVICE_TRANSFER, false);
     }
 }
diff --git a/packages/SettingsLib/BannerMessagePreference/Android.bp b/packages/SettingsLib/BannerMessagePreference/Android.bp
index 095975a..82e837b 100644
--- a/packages/SettingsLib/BannerMessagePreference/Android.bp
+++ b/packages/SettingsLib/BannerMessagePreference/Android.bp
@@ -1,3 +1,12 @@
+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: "SettingsLibBannerMessagePreference",
 
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
index c23ff05..ed49bf4 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
@@ -1,3 +1,12 @@
+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: "SettingsLibCollapsingToolbarBaseActivity",
 
diff --git a/packages/SettingsLib/EmergencyNumber/Android.bp b/packages/SettingsLib/EmergencyNumber/Android.bp
index 3c41f78..25b4905 100644
--- a/packages/SettingsLib/EmergencyNumber/Android.bp
+++ b/packages/SettingsLib/EmergencyNumber/Android.bp
@@ -1,3 +1,12 @@
+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: "SettingsLibEmergencyNumber",
 
diff --git a/packages/SettingsLib/FooterPreference/Android.bp b/packages/SettingsLib/FooterPreference/Android.bp
index 1af967f..11f39e7 100644
--- a/packages/SettingsLib/FooterPreference/Android.bp
+++ b/packages/SettingsLib/FooterPreference/Android.bp
@@ -1,3 +1,12 @@
+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: "SettingsLibFooterPreference",
 
diff --git a/packages/SettingsLib/MainSwitchPreference/Android.bp b/packages/SettingsLib/MainSwitchPreference/Android.bp
index 1dc18f5..1feec21 100644
--- a/packages/SettingsLib/MainSwitchPreference/Android.bp
+++ b/packages/SettingsLib/MainSwitchPreference/Android.bp
@@ -1,3 +1,12 @@
+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: "SettingsLibMainSwitchPreference",
 
diff --git a/packages/SettingsLib/TopIntroPreference/Android.bp b/packages/SettingsLib/TopIntroPreference/Android.bp
index 03becbd..9577281 100644
--- a/packages/SettingsLib/TopIntroPreference/Android.bp
+++ b/packages/SettingsLib/TopIntroPreference/Android.bp
@@ -1,3 +1,12 @@
+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: "SettingsLibTopIntroPreference",
 
diff --git a/packages/SettingsLib/UsageProgressBarPreference/Android.bp b/packages/SettingsLib/UsageProgressBarPreference/Android.bp
index 3331550..ad6e7ab 100644
--- a/packages/SettingsLib/UsageProgressBarPreference/Android.bp
+++ b/packages/SettingsLib/UsageProgressBarPreference/Android.bp
@@ -1,3 +1,12 @@
+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: "SettingsLibUsageProgressBarPreference",
 
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 4b253c4..eafc614 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Ignoreer kodewisselingverstekke"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Aktiveer kodewisseling"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Aanvaar dat programme moderne formate steun"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Wys kodewisselingkennisgewings"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Lopende dienste"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Sien en beheer dienste wat tans aktief is"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementering"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 4982f82..547d0af 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"የትራንስኮዲንግ ነባሪዎችን ሻር"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ትራንስኮዲንግን ያንቁ"</string>
     <string name="transcode_default" msgid="3784803084573509491">"መተግበሪያዎች ዘመናዊ ቅርጸቶችን እንደሚደግፉ አድርገው ይቁጠሩ"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"ትራንስኮዲንግ ማሳወቂያዎችን አሳይ"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"አሂድ አገልግሎቶች"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"በአሁኑጊዜ እየሄዱ ያሉ አገልግሎቶችን ተቆጣጠር እና እይ"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"የWebView ትግበራ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 5eaefd0..c6a1d18f 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"إلغاء الإعدادات التلقائية لتحويل الترميز"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"تفعيل تحويل الترميز"</string>
     <string name="transcode_default" msgid="3784803084573509491">"افتراض أن التطبيق يتوافق مع التنسيقات الحديثة"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"إظهار إشعارات تحويل الترميز"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"الخدمات قيد التشغيل"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"عرض الخدمات قيد التشغيل في الوقت الحالي والتحكم فيها"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"‏تطبيق WebView"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 571f7d0..e9deb46 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ট্ৰেন্সক’ডিং ডিফ’ল্ট অ’ভাৰৰাইড কৰক"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ট্ৰেন্সক’ডিং সক্ষম কৰক"</string>
     <string name="transcode_default" msgid="3784803084573509491">"এপে আধুনিক ফৰ্মেট সমৰ্থন কৰে বুলি ধৰি লওক"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"ট্ৰান্সক\'ডিঙৰ জাননী দেখুৱাওক"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"চলিত সেৱা"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"বৰ্তমান চলি থকা সেৱাসমূহ চাওক আৰু নিয়ন্ত্ৰণ কৰক"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"ৱেবভিউ প্ৰয়োগ"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 36a13f5..d04409c 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Yenidən kodlaşdırma defoltlarını əvəzləyin"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Yenidən kodlaşdırmanı aktiv edin"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Tətbiqlərin müasir formatları dəstəklədiyini qəbul edin"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Kod dəyişmə bildirişlərini göstərin"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"İşləyən xidmətlər"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Hazırda prosesdə olan xidmətləri görüntüləyin və onlara nəzarət edin"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView icrası"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index d7cc909..ecd70a2 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Zameni podrazumevana podešavanja transkodiranja"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Omogući transkodiranje"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Podrazumevaj da aplikacije podržavaju moderne formate"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Prikazuj obaveštenja o transkodiranju"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Pokrenute usluge"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Prikaz i kontrola trenutno pokrenutih usluga"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Primena WebView-a"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 01201b3..6a3b961 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Перавызначыць стандартныя налады перакадзіравання"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Уключыць перакадзіраванне"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Лічыца, што праграмы падтрымліваюць сучасныя фарматы"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Паказваць апавяшчэнні пра перакадзіраванне"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Запушчаныя службы"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Прагляд запушчаных службаў i кіраванне iмi"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Рэалізацыя WebView"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 00f5e71..d2bf705 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Отмяна на стандартните настройки за прекодирането"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Активиране на прекодирането"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Предполагане, че приложенията поддържат съвременни формати"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Показване на известията за прекодиране"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Изпълнявани услуги"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Преглед и контрол върху изпълняващите се понастоящем услуги"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Внедряване на WebView"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 43bb758..3ccf0e4 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ট্রান্সকোডিং ডিফল্ট সেটিংস ওভাররাইড করুন"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ট্রান্সকোডিং চালু করুন"</string>
     <string name="transcode_default" msgid="3784803084573509491">"অ্যাপ মর্ডার্ন ফর্ম্যাটে কাজ করবে বলে ধরে নিন"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"ট্রান্সকোডিং বিজ্ঞপ্তি দেখুন"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"এখন চলছে যে পরিষেবাগুলি"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"বর্তমান চলমান পরিষেবাগুলি দেখুন এবং নিয়ন্ত্রণ করুন"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"ওয়েবভিউ প্রয়োগ"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index dacacfb..f01eef3 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Zaobiđi zadane postavke transkodiranja"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Omogući transkodiranje"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Pretpostavi da aplikacije podržavaju moderne formate"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Prikaži obavještenja o transkodiranju"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Pokrenute usluge"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Prikaz i kontrola trenutno pokrenutih usluga"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Postavljanje WebViewa"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 17482ed..7069999 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Substitueix els valors predeterminats de la transcodificació"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Activa la transcodificació"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Assumeix que les aplicacions són compatibles amb formats moderns"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Mostra les notificacions de transcodificació"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Serveis en execució"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Visualitza i controla els serveis en execució"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementació de WebView"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index ddd5c52..c677fef 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Přepsat výchozí nastavení překódování"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Povolit překódování"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Předpokládat, že aplikace podporují moderní formáty"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Zobrazit oznámení o překódování"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Spuštěné služby"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Umožňuje zobrazit a ovládat aktuálně spuštěné služby"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementace WebView"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 421ed74..84247a6 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Tilsidesæt standardindstillingerne for omkodning"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Aktivér omkodning"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Gå ud fra, at apps understøtter moderne formater"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Vis notifikationer for omkodning"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Kørende tjenester"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Vis og administrer kørende tjenester"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementering"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 7cb994c..4cc79d3 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Standardeinstellungen für Transcodierung überschreiben"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Transcodierung aktivieren"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Voraussetzen, dass Apps moderne Formate unterstützen"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Benachrichtigungen zur Transcodierung anzeigen"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Aktive Dienste"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Momentan ausgeführte Dienste anzeigen und steuern"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-Implementierung"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 7a73ccd..30705a1 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Παράκαμψη προεπιλογών διακωδικοποίησης"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Ενεργοποίηση διακωδικοποίησης"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Να θεωρείται ότι οι εφαρμογές χρησιμοποιούν σύγχρονες μορφές"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Εμφάνιση ειδοποιήσεων διακωδικοποίησης"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Υπηρεσίες που εκτελούνται"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Προβολή και έλεγχος των εφαρμογών που εκτελούνται αυτή τη στιγμή"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Υλοποίηση WebView"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 6241953..b3d80ab 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Override transcoding defaults"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Enable transcoding"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Assume apps support modern formats"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Show transcoding notifications"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Running services"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"View and control currently running services"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 198fee4..ecf97ad 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Override transcoding defaults"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Enable transcoding"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Assume apps support modern formats"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Show transcoding notifications"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Running services"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"View and control currently running services"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 6241953..b3d80ab 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Override transcoding defaults"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Enable transcoding"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Assume apps support modern formats"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Show transcoding notifications"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Running services"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"View and control currently running services"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 6241953..b3d80ab 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Override transcoding defaults"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Enable transcoding"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Assume apps support modern formats"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Show transcoding notifications"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Running services"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"View and control currently running services"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 27cd8b3..c3a3f3f 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‎‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‎‏‏‏‏‎‏‏‏‎‏‏‏‏‎‎‎‎‎‏‏‏‎‏‎‏‏‎‏‏‏‏‎‎‏‎‎Override transcoding defaults‎‏‎‎‏‎"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‏‎‏‏‏‎‏‏‎‎‎‏‎‏‏‏‎‏‎‏‎‎‎‎‏‎‎‎‏‏‏‏‎‎‏‏‏‎‏‏‎‎‏‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎Enable transcoding‎‏‎‎‏‎"</string>
     <string name="transcode_default" msgid="3784803084573509491">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‏‏‎‎‏‎‏‎‎‏‎‎‏‎‏‏‎‏‎‎‏‎‎‏‎‎‎‏‏‎‎‏‏‏‎‏‎‎‎‎‏‏‏‎‏‏‏‎‎‏‏‎Assume apps support modern formats‎‏‎‎‏‎"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‏‎‏‎‏‎‏‏‏‎‏‎‏‏‏‏‎‏‎‎‏‎‏‎‎‏‏‏‏‏‎‏‏‏‏‎‎‎‏‎‎‎‏‏‏‎‎‎‎‎‏‎‎‎‎Show transcoding notifications‎‏‎‎‏‎"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‎‎‏‏‎‏‏‏‎‎‎‏‎‎‎‎‏‎‎‏‏‏‏‎‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‎‎‏‏‎Running services‎‏‎‎‏‎"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‏‎‏‎‎‎‎‏‎‎‎‏‏‎‏‏‎‎‏‏‎‎‏‏‎‏‎‏‏‏‏‏‎‎‎‎‎‏‎‏‎‏‎‏‎‏‎‏‎‎‎‎‎‎‏‏‏‏‎View and control currently running services‎‏‎‎‏‎"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‏‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‏‏‎‎‎‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‏‎‏‎‏‎‏‏‏‏‏‏‏‏‎WebView implementation‎‏‎‎‏‎"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 5e5b39a..eb2a23b 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Anular los valores predeterminados de transcodificación"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Habilitar la transcodificación"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Suponer que las apps admiten formatos modernos"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Mostrar notificaciones de transcodificación"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"En ejecución"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Ver y controlar servicios actuales en ejecución"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementación de WebView"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 8d79177..fe9984b 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Anular valores predeterminados de transcodificación"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Habilitar transcodificación"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Considerar que las aplicaciones admiten formatos modernos"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Mostrar notificaciones de transcodificación"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Servicios en ejecución"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Ver y controlar los servicios en ejecución"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementación de WebView"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 18ee623..c70700d 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Alista transkodeerimise vaikeseaded"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Luba transkodeerimine"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Oleta, et rakendused toetavad kaasaegseid vorminguid"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Kuva transkodeerimise märguanded"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Käitatud teenused"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Praegu käitatud teenuste vaatamine ja juhtimine"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView\' rakendamine"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 71be593..09c964a 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Ez erabili transkodetzearen balio lehenetsiak"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Gaitu transkodetzea"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Arduratu aplikazioek formatu modernoak onartzeaz"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Erakutsi transkodetze-jakinarazpenak"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Abian diren zerbitzuak"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Ikusi eta kontrolatu une honetan abian diren zerbitzuak"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView inplementazioa"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 81a2cf8..22cd6ae 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ملغی کردن پیش‌فرض‌های تراتبدیل"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"فعال کردن تراتبدیل"</string>
     <string name="transcode_default" msgid="3784803084573509491">"فرض شود برنامه‌ها از قالب‌های مدرن پشتیبانی می‌کنند"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"نمایش اعلان‌های تراتبدیل"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"سرویس‌های در حال اجرا"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"مشاهده و کنترل سرویس‌های در حال اجرای فعلی"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"اجرای وب‌نما"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 0703c45..22dde69 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Ohita transkoodauksen oletukset"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Salli transkoodaus"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Oleta, että sovellukset tukevat nykyaikaisia formaatteja"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Näytä transkoodausilmoituksia"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Käynnissä olevat palvelut"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Tarkastele ja hallitse käynnissä olevia palveluita."</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-käyttöönotto"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 5b8c938..d189f72 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Remplacer les valeurs par défaut de transcodage"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Activer le transcodage"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Présumer que les applications prennent en charge les formats modernes"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Afficher les notifications de transcodage"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Services en cours d\'exécution"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Afficher et contrôler les services en cours d\'exécution"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Mise en œuvre WebView"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index b025357..49d7faa 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Ignorer les paramètres de transcodage par défaut"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Activer le transcodage"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Supposer que les applications sont compatibles avec les formats modernes"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Afficher les notifications de transcodage"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Services en cours d\'exécution"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Afficher et contrôler les services en cours d\'exécution"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Mise en œuvre WebView"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index d68595e..0922c3d 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Anular valores predeterminados de transcodificación"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Activar transcodificación"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Considerar que as aplicacións admiten formatos modernos"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Mostrar notificacións de transcodificación"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Servizos en uso"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Comproba e controla os servizos actualmente en uso"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementación de WebView"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index e151ddb..10c5cc8 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ફૉર્મેટ બદલવાની પ્રક્રિયાના ડિફૉલ્ટ સેટિંગ ઓવરરાઇડ કરો"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ફૉર્મેટ બદલવાની પ્રક્રિયા ચાલુ કરો"</string>
     <string name="transcode_default" msgid="3784803084573509491">"ધારો કે ઍપ આધુનિક ફૉર્મેટ પર કામ કરે છે"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"ફૉર્મેટ બદલવાની પ્રક્રિયાના નોટિફિકેશન બતાવો"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"ચાલુ સેવાઓ"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"હાલમાં ચાલતી સેવાઓ જુઓ અને નિયંત્રિત કરો"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView અમલીકરણ"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index beab7bd..ea25406 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ट्रांसकोडिंग की डिफ़ॉल्ट सेटिंग बदलें"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ट्रांसकोडिंग चालू करें"</string>
     <string name="transcode_default" msgid="3784803084573509491">"मानकर चलें कि ऐप्लिकेशन, नए फ़ॉर्मैट के साथ काम करेंगे"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"ट्रांसकोडिंग की सूचनाएं दिखाएं"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"चल रही सेवाएं"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"इस समय चल रही सेवाओं को देखें और नियंत्रित करें"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"वेबव्यू लागू करें"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 8989cc9..27a7a6e 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Nadjačaj zadane postavke konvertiranja"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Omogući konvertiranje"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Pretpostavi da aplikacije podržavaju moderne formate"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Prikaži obavijesti o konvertiranju"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Pokrenute usluge"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Pregledajte i kontrolirajte pokrenute usluge"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementacija WebViewa"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 7c5a1a0..70a48b6 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Az átkódolás alapértelmezett beállításainak felülbírálása"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Átkódolás engedélyezése"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Annak feltételezése, hogy az alkalmazások támogatják a modern formátumokat"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Átkódolási értesítések megjelenítése"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Futó szolgáltatások"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"A jelenleg futó szolgáltatások megtekintése és vezérlése"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-megvalósítás"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 6684d35..c39e966 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Չեղարկել վերակոդավորման կանխադրված կարգավորումները"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Միացնել վերակոդավորումը"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Ենթադրել, որ հավելվածներն աջակցում են ժամանակակից ձևաչափեր"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Ցուցադրել անդրկոդավորման ծանուցումներ"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Աշխատող ծառայություններ"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Դիտել և վերահսկել ընթացիկ աշխատող ծառայությունները"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ծառայություն"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 075444c..037c1b3 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Ganti default transcoding"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Aktifkan transcoding"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Asumsikan aplikasi mendukung format modern"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Tampilkan notifikasi transcoding"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Layanan yang sedang berjalan"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Melihat dan mengontrol layanan yang sedang berjalan"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Penerapan WebView"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index b079f4d..3f87830 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Hnekkja sjálfgefinni umkóðun"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Kveikja á umkóðun"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Gera ráð fyrir að forrit styðji nútímasnið"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Sýna umkóðunartilkynningar"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Þjónustur í gangi"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Skoða og stjórna þjónustum í gangi"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Innleiðing WebView"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index bf525c5..80ab57b 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Sostituisci impostazioni predefinite transcodifica"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Attiva transcodifica"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Presupponi che le app supportino i formati moderni"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Mostra notifiche relative alla transcodifica"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Servizi in esecuzione"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Visualizza e controlla i servizi attualmente in esecuzione"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementazione di WebView"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 9055e77..4355f31 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ביטול ברירות המחדל של המרת קידוד"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"הפעלת המרת קידוד"</string>
     <string name="transcode_default" msgid="3784803084573509491">"הנחת העבודה היא שאפליקציות תומכות בפורמטים מודרניים"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"הצגת התראות לגבי המרת קידוד"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"שירותים פועלים"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"הצגת השירותים הפועלים כעת ושליטה בהם"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"‏יישום WebView"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 7fa0df9..ea4a683 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"デフォルトのコード変換をオーバーライド"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"コード変換を有効にする"</string>
     <string name="transcode_default" msgid="3784803084573509491">"アプリによる最新形式のサポートを想定"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"コード変換に関する通知の表示"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"実行中のサービス"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"現在実行中のサービスを表示して制御する"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView の実装"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 7dd1eee..5798a46 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ტრანსკოდირების ნაგულისხმევების უგულებელყოფა"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ტრანსკოდირების ჩართვა"</string>
     <string name="transcode_default" msgid="3784803084573509491">"დაშვება, რომ აპებს აქვთ თანამედროვე ფორმატების მხარდაჭერა"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"ტრანსკოდირების შეტყობინებების ჩვენება"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"მიმდინარე სერვისები"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"ამჟამად მოქმედი სერვისების ნახვა და მართვა"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView რეალიზაცია"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 59b1d63..5ce4e3a 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Қайта қодтаудың әдепкі параметрлерін қайта анықтау"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Қайта кодтауды қосу"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Қолданбалар қазіргі заманғы форматтарды қолдайды делік"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Қайта кодтау хабарландыруларын көрсету"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Қосылып тұрған қызметтер"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Қазір істеп тұрған қызметтерді көру және басқару"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView қызметі"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index b01839d..e6f2cb0 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"លុបពីលើលំនាំដើម​នៃការបំប្លែងកូដ"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"បើក​ការបំប្លែងកូដ"</string>
     <string name="transcode_default" msgid="3784803084573509491">"សន្មតថាកម្មវិធី​អាចប្រើ​ទម្រង់ទំនើបបាន"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"បង្ហាញការជូនដំណឹង​អំពីការបំប្លែងកូដ"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"សេវាកម្ម​កំពុង​ដំណើរការ"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"មើល និង​គ្រប់គ្រង​សេវាកម្ម​កំពុង​ដំណើរការ​បច្ចុប្បន្ន"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"ការអនុវត្ត WebView"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 217c917..561e6be 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -404,6 +404,8 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ಟ್ರಾನ್ಸ್‌ಕೋಡಿಂಗ್ ಡೀಫಾಲ್ಟ್‌ಗಳನ್ನು ಅತಿಕ್ರಮಿಸಿ"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ಟ್ರಾನ್ಸ್‌ಕೋಡಿಂಗ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
     <string name="transcode_default" msgid="3784803084573509491">"ಆ್ಯಪ್‌ಗಳು ಆಧುನಿಕ ಫಾರ್ಮ್ಯಾಟ್‌ಗಳನ್ನು ಬೆಂಬಲಿಸುತ್ತದೆ ಎಂದು ಊಹಿಸಿ"</string>
+    <!-- no translation found for transcode_notification (5560515979793436168) -->
+    <skip />
     <string name="runningservices_settings_title" msgid="6460099290493086515">"ರನ್‌ ಆಗುತ್ತಿರುವ ಸೇವೆಗಳು"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"ಈಗ ರನ್‌ ಆಗುತ್ತಿರುವ ಸೇವೆಗಳನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ನಿಯಂತ್ರಿಸಿ"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ಹೊಂದಿಸಿ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 0b8c71d..cd3b8b8 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"트랜스코딩 기본값 재정의"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"트랜스코딩 사용"</string>
     <string name="transcode_default" msgid="3784803084573509491">"앱이 최신 형식을 지원하는 것으로 가정"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"트랜스코딩 알림 표시"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"실행 중인 서비스"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"현재 실행 중인 서비스 보기 및 제어"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 구현"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index cad00a3..1990353 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Демейки жүргүзүлгөн транскоддоону өзгөртүп коюу"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Транскоддоо жүргүзүүнү иштетүү"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Колдонмолордо заманбап форматтар колдоого алынат"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Транскоддоо билдирмелерин көрсөтүү"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Иштеп жаткан кызматтар"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Учурда иштеп жаткан кызматтарды көрүп, көзөмөлдөп турасыз"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView кызматы"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 5bd297e..4997ea1 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ຍົກເລີກຄ່າເລີ່ມຕົ້ນການ​ປ່ຽນ​ຮູບ​ແບບ​ລະ​ຫັດ"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ເປີດການນຳໃຊ້ການ​ປ່ຽນ​ຮູບ​ແບບ​ລະ​ຫັດ"</string>
     <string name="transcode_default" msgid="3784803084573509491">"ສົມມຸດວ່າແອັບຮອງຮັບຮູບແບບສະໄໝໃໝ່"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"ສະແດງການແຈ້ງເຕືອນການ​ປ່ຽນ​ຮູບ​ແບບ​ລະ​ຫັດ"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"ບໍລິການທີ່ເຮັດວຽກຢູ່"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"ເບິ່ງ ແລະຈັດການບໍລິການທີ່ກຳລັງເຮັດວຽກຢູ່ໃນປັດຈຸບັນ"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"ການຈັດຕັ້ງປະຕິບັດ WebView"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 8c7485f..ec3cb0d 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Perkodavimo numatytųjų nustatymų nepaisymas"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Perkodavimo įgalinimas"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Manoma, kad programos palaiko modernius formatus"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Rodyti perkodavimo pranešimus"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Vykdomos paslaugos"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Žiūrėti ir valdyti dabar vykdomas paslaugas"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"„WebView“ diegimas"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index d8020c7..ff9f0a1 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Ignorēt pārkodēšanas noklusējuma iestatījumus"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Iespējot pārkodēšanu"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Pieņemt, ka lietotnēs tiek atbalstīti moderni formāti"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Rādīt paziņojumus par pārkodēšanu"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Aktīvie pakalpojumi"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Pašreiz darbojošos pakalpojumu skatīšana un vadība"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ieviešana"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index e4c8425..507f65c 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Отфрли стандардни вредности за транскодирање"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Овозможи транскодирање"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Претпостави дека апликациите поддржуваат модерни формати"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Прикажувај известувања за транскодирање"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Активни услуги"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Погледнете и контролирајте услуги што се моментално активни"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Воведување WebView"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 28422c9..8a09801 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ട്രാൻസ്കോഡ് ചെയ്യൽ ഡിഫോൾട്ടുകൾ അസാധുവാക്കുക"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ട്രാൻസ്കോഡ് ചെയ്യൽ പ്രവർത്തനക്ഷമമാക്കുക"</string>
     <string name="transcode_default" msgid="3784803084573509491">"ആപ്പുകൾ ആധുനിക ഫോർമാറ്റുകളെ പിന്തുണയ്ക്കുമെന്ന് കരുതുക"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"ട്രാൻസ്കോഡ് ചെയ്യൽ അറിയിപ്പുകൾ കാണിക്കുക"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"പ്രവർത്തിക്കുന്ന സേവനങ്ങൾ"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"നിലവിൽ പ്രവർത്തിക്കുന്ന സേവനങ്ങൾ കാണുക, നിയന്ത്രിക്കുക"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView നടപ്പാക്കൽ"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 0d78ea9..27ca8f5 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Хөрвүүлгийн өгөгдмөлийг дарах"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Хөрвүүлгийг идэвхжүүлэх"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Аппыг орчин үеийн форматыг дэмждэг гэж үздэг"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Хөрвүүлгийн мэдэгдэл харуулах"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Ажиллаж байгаа үйлчилгээнүүд"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Одоо ажиллаж байгаа үйлчилгээнүүдийг харах болон хянах"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView хэрэгжилт"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index d27f705..b6c5460 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -404,6 +404,8 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ट्रान्सकोडिंग डीफॉल्ट ओव्हरराइड करा"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ट्रान्सकोडिंग सुरू करा"</string>
     <string name="transcode_default" msgid="3784803084573509491">"असे गृहीत धरा की, ॲप्स आधुनिक फॉरमॅटना सपोर्ट करतात"</string>
+    <!-- no translation found for transcode_notification (5560515979793436168) -->
+    <skip />
     <string name="runningservices_settings_title" msgid="6460099290493086515">"सुरू सेवा"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"सध्या सुरू असलेल्या सेवा पहा आणि नियंत्रित करा"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"वेबदृश्य अंमलबजावणी"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index c5a2c62..53a4398 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Batalkan transpengekodan lalai"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Dayakan transpengekodan"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Mengambil alih sokongan apl format moden"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Tunjukkan pemberitahuan transpengekodan"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Perkhidmatan dijalankan"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Lihat dan kawal perkhidmatan yang sedang dijalankan"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Pelaksanaan WebView"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index ed34f7d..0fef5ab 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -307,7 +307,7 @@
     <string name="adb_keys_warning_message" msgid="2968555274488101220">"သင် ယခင်က ခွင့်ပြုခဲ့သော ကွန်ပျူတာအားလုံးမှ ယူအက်စ်ဘီ အမှားစစ်ခွင့်ကို ရုတ်သိမ်းမည်လား ?"</string>
     <string name="dev_settings_warning_title" msgid="8251234890169074553">"တည်ဆောက်ပြုပြင်ရန်ဆက်တင်များကို အသုံးပြုခွင့်ပေးမည်လား?"</string>
     <string name="dev_settings_warning_message" msgid="37741686486073668">"ဤဆက်တင်းများကို တည်ဆောက်ပြုပြင်ရာတွင် သုံးရန်အတွက်သာ ရည်ရွယ်သည်။ ၎င်းတို့သည် သင်၏စက်နှင့် အပလီကေးရှင်းများကို ရပ်စေခြင်း သို့ လုပ်ဆောင်ချက်မမှန်ကန်ခြင်းများ ဖြစ်ပေါ်စေနိုင်သည်။"</string>
-    <string name="verify_apps_over_usb_title" msgid="6031809675604442636">"USB ဖြင့် အက်ပ်များကို အတည်ပြုစိစစ်ရန်"</string>
+    <string name="verify_apps_over_usb_title" msgid="6031809675604442636">"USB ဖြင့် အက်ပ်များစိစစ်ရန်"</string>
     <string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"ADB/ADT မှတစ်ဆင့် ထည့်သွင်းသော အက်ပ်များ အန္တရာယ်ဖြစ်နိုင်ခြင်း ရှိမရှိ စစ်ဆေးသည်။"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"အမည်မရှိသော (MAC လိပ်စာများသာပါသော) ဘလူးတုသ်စက်ပစ္စည်းများကို ပြသပါမည်"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"ချိတ်ဆက်ထားသည့် ကိရိယာတွင် လက်မခံနိုင်လောက်အောင် ဆူညံ သို့မဟုတ် ထိန်းညှိမရနိုင်သော အသံပိုင်းပြဿနာ ရှိခဲ့လျှင် ဘလူးတုသ် ပကတိ အသံနှုန်းကို ပိတ်ပါ။"</string>
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"အမျိုးအစားပြောင်းခြင်း၏ မူရင်းဆက်တင်များကို အစားထိုးရန်"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"အမျိုးအစားပြောင်းခြင်းကို ဖွင့်ရန်"</string>
     <string name="transcode_default" msgid="3784803084573509491">"ဤအက်ပ်များက ဖော်မက်အသစ်များကို ပံ့ပိုးသည်"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"အမျိုးအစားပြောင်းခြင်း အကြောင်းကြားချက်များကို ပြရန်"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"အလုပ်လုပ်နေသောဝန်ဆောင်မှုများ"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"လက်ရှိ ဝန်ဆောင်မှုများကို ကြည့်ရှု ထိန်းသိမ်းသည်"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView အကောင်အထည်ဖော်မှု"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 5366e7e..0ca8d51 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Overstyr omkodingsstandarder"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Slå på omkoding"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Anta at apper støtter moderne formater"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Vis omkodingsvarsler"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Aktive tjenester"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Se og kontrollér tjenester som kjører"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementering"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index cde7b80..75b4537 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -404,6 +404,8 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ट्रान्सकोडिङसम्बन्धी पूर्वनिर्धारित सेटिङ परिवर्तन गर्नुहोस्"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ट्रान्सकोडिङ अन गर्नुहोस्"</string>
     <string name="transcode_default" msgid="3784803084573509491">"एपहरूमा आधुनिक फर्म्याट प्रयोग गर्न मिल्छ भनी मान्नुहोस्"</string>
+    <!-- no translation found for transcode_notification (5560515979793436168) -->
+    <skip />
     <string name="runningservices_settings_title" msgid="6460099290493086515">"चलिरहेका सेवाहरू"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"हाल चालु भइरहेका सेवाहरू हेर्नुहोस् र नियन्त्रण गर्नुहोस्"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView कार्यान्वयन"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index bb1402a..71d6acc 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Standaardwaarden voor transcodering overschrijven"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Transcodering inschakelen"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Aannemen dat apps moderne indelingen ondersteunen"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Transcoderingsmeldingen laten zien"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Actieve services"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Services die momenteel actief zijn, weergeven en beheren"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementatie"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 90fc8bc..1d6e34f 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ଟ୍ରାନ୍ସକୋଡିଂ ଡିଫଲ୍ଟଗୁଡ଼ିକୁ ଓଭରରାଇଡ୍ କରନ୍ତୁ"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ଟ୍ରାନ୍ସକୋଡିଂକୁ ସକ୍ଷମ କରନ୍ତୁ"</string>
     <string name="transcode_default" msgid="3784803084573509491">"ଧରିନିଅନ୍ତୁ ଆପଗୁଡ଼ିକ ଆଧୁନିକ ଫର୍ମାଟଗୁଡ଼ିକୁ ସମର୍ଥନ କରେ"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"ଟ୍ରାନ୍ସକୋଡିଂ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଦେଖାନ୍ତୁ"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"ଚାଲୁଥିବା ସେବାଗୁଡ଼ିକ"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"ଏବେ ଚାଲୁଥିବା ସେବାଗୁଡ଼ିକୁ ଦେଖନ୍ତୁ ଓ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"ୱେବ୍‌ଭ୍ୟୁ ପ୍ରୟୋଗ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 4c20e19..9d91aae 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -404,6 +404,8 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਦੀਆਂ ਪੂਰਵ-ਨਿਰਧਾਰਤ ਸੈਟਿੰਗਾਂ ਨੂੰ ਓਵਰਰਾਈਡ ਕਰੋ"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਚਾਲੂ ਕਰੋ"</string>
     <string name="transcode_default" msgid="3784803084573509491">"ਮੰਨ ਲਓ ਕਿ ਐਪਾਂ ਆਧੁਨਿਕ ਫਾਰਮੈਟਾਂ ਦਾ ਸਮਰਥਨ ਕਰਦੀਆਂ ਹਨ"</string>
+    <!-- no translation found for transcode_notification (5560515979793436168) -->
+    <skip />
     <string name="runningservices_settings_title" msgid="6460099290493086515">"ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"ਇਸ ਵੇਲੇ ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ ਦੇਖੋ ਅਤੇ ਇਹਨਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ਅਮਲ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 6d037d8..f48b05f 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Zastąp ustawienia domyślne transkodowania"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Włącz transkodowanie"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Zakładaj, że aplikacje obsługują nowoczesne formaty"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Pokaż powiadomienia transkodowania"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Uruchomione usługi"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Wyświetl obecnie uruchomione usługi i nimi zarządzaj"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementacja WebView"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 3feed99..b9c9191 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Substituir os padrões de transcodificação"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Ativar transcodificação"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Considerar que os apps são compatíveis com formatos modernos"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Mostrar notificações de transcodificação"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Serviços em execução"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Visualizar e controlar os serviços em execução no momento"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementação do WebView"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index a886aa9..57e38c078 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Substituir as predefinições da transcodificação"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Ativar a transcodificação"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Assumir que as apps suportam formatos modernos"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Mostrar notificações de transcodificação"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Serviços em execução"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Ver e controlar os serviços actualmente em execução"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementação WebView"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 3feed99..b9c9191 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Substituir os padrões de transcodificação"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Ativar transcodificação"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Considerar que os apps são compatíveis com formatos modernos"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Mostrar notificações de transcodificação"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Serviços em execução"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Visualizar e controlar os serviços em execução no momento"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementação do WebView"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 7fbe622..c2da73c 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Modificați setările prestabilite de transcodare"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Activați transcodarea"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Presupuneți că aplicațiile acceptă formatele moderne"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Vedeți notificările privind transcodarea"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Servicii în curs de funcționare"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Vedeți și controlați serviciile care funcționează în prezent"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementare WebView"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 1669df6..efcce75 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Переопределять настройки транскодирования по умолчанию"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Включить перекодирование"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Считать, что приложения поддерживают современные форматы кодирования"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Показывать уведомления о перекодировании"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Работающие службы"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Просмотр и управление работающими службами"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Сервис WebView"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 1fdd968..590e0e4 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ට්‍රාන්ස්කෝඩින් පෙරනිමි ප්‍රතික්ෂේප කරන්න"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ට්‍රාන්ස්කෝඩින් සබල කරන්න"</string>
     <string name="transcode_default" msgid="3784803084573509491">"යෙදුම් නවීන ආකෘති සඳහා සහාය දක්වයි යැයි උපකල්පනය කරමු"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"ට්‍රාන්ස්කෝඩින් දැනුම්දීම් පෙන්වන්න"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"ධාවනය වන සේවා"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"දැනට ධාවනය වන සේවා බලන්න සහ පාලනය කරන්න"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ක්‍රියාත්මක කිරීම"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 03b454e..c817ed0 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Prepísať predvolené nastavenia prekódovania"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Povoliť prekódovanie"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Prepdokladať, že aplikácie podporujú moderné formáty"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Zobraziť upozornenia prekódovania"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Spustené služby"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Zobrazovať a riadiť aktuálne spustené služby"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementácia WebView"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 73b4818..464b235 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Preglasi privzete nastavitve prekodiranja"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Omogoči prekodiranje"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Aplikacije naj bi podpirale sodobne oblike zapisov"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Prikaz obvestil o prekodiranju"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Zagnane storitve"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Preglejte in nadzorujte storitve, ki so trenutno zagnane"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Izvedba spletnega pogleda"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index a07bb2b..a2a63e1 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Anulo parazgjedhjet e transkodimit"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Aktivizo transkodimin"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Supozo se aplikacionet i mbështetin formatet moderne"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Shfaq njoftimet e transkodimit"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Shërbimet në ekzekutim"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Shiko dhe kontrollo shërbimet që po ekzekutohen aktualisht"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Zbatimi i WebView"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 0faaf83..2119303 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Замени подразумевана подешавања транскодирања"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Омогући транскодирање"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Подразумевај да апликације подржавају модерне формате"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Приказуј обавештења о транскодирању"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Покренуте услуге"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Приказ и контрола тренутно покренутих услуга"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Примена WebView-а"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 87606d0..c7a2169 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Åsidosätta standardinställningar för omkodning"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Aktivera omkodning"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Anta att appar har stöd för moderna format"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Visa aviseringar för omkodning"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Aktiva tjänster"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Visa och styr aktiva tjänster"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementering"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index d479b0b..60014f4 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Batilisha chaguomsingi za kubadilisha miundo ya faili"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Ruhusu ubadilishaji wa miundo ya faili"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Chukulia kuwa programu zinatumia miundo ya kisasa"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Onyesha arifa za kubadilisha muundo wa faili"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Huduma zinazoendeshwa"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Onyesha na udhibiti huduma zinazoendeshwa kwa sasa"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Utekelezaji wa WebView"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 247889b..82cce12 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"இயல்புநிலை குறிமாற்றங்களை மீறிச் செயல்படு"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"குறிமாற்றத்தை இயக்கு"</string>
     <string name="transcode_default" msgid="3784803084573509491">"ஆப்ஸ் மாடர்ன் வடிவங்களை ஆதரிக்கும்படி அமை"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"குறிமாற்ற அறிவிப்புகளைக் காட்டு"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"இயங்கும் சேவைகள்"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"தற்போது இயக்கத்தில் இருக்கும் சேவைகளைப் பார்த்து கட்டுப்படுத்து"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView செயல்படுத்தல்"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index b5d584f..3b04eb4 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ట్రాన్స్‌కోడింగ్ ఆటోమేటిక్ సెట్టింగ్‌లను ఓవర్‌రైడ్ చేయండి"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ట్రాన్స్‌కోడింగ్‌ను ఎనేబుల్ చేయండి"</string>
     <string name="transcode_default" msgid="3784803084573509491">"యాప్‌లు ఆధునిక ఫార్మాట్‌లకు సపోర్ట్ చేస్తాయని అనుకోండి"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"ట్రాన్స్‌కోడింగ్ నోటిఫికేషన్‌లను చూపండి"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"అమలులో ఉన్న సేవలు"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"ప్రస్తుతం అమలులో ఉన్న సేవలను వీక్షించండి మరియు నియంత్రించండి"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"వెబ్ వీక్షణ అమలు"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index dc1514f..a970321 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ลบล้างค่าเริ่มต้นของการแปลง"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"เปิดใช้การแปลง"</string>
     <string name="transcode_default" msgid="3784803084573509491">"ถือว่าแอปรองรับรูปแบบสมัยใหม่"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"แสดงการแจ้งเตือนการแปลง"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"บริการที่ทำงานอยู่"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"ดูและควบคุมบริการที่ทำงานอยู่"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"การใช้งาน WebView"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 7c4ceec..bedd005 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"I-override ang mga default ng pagta-transcode"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"I-enable ang pagta-transcode"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Ipagpalagay na sinusuportahan ng mga app ang mga modernong format"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Ipakita ang mga notification sa pag-transcode"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Mga tumatakbong serbisyo"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Tingnan at kontrolin ang mga kasalukuyang tumatakbong serbisyo"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Pagpapatupad sa WebView"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 2b5dff15..2b2b44e 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Kod dönüştürme varsayılanlarını geçersiz kıl"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Kod dönüştürmeyi etkinleştir"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Uygulamaların modern biçimleri desteklediğini varsay"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Kod dönüştürme bildirimlerini göster"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Çalışan hizmetler"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Şu anda çalışan hizmetleri görüntüle ve denetle"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Web Görünümü kullanımı"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 6fff40d..9c5e2aa 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Замінити стандартні налаштування перекодування"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Увімкнути перекодування"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Вважати, що додатки підтримують сучасні формати"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Показувати сповіщення про перекодування"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Запущені сервіси"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Переглянути й налаштувати запущені сервіси"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Застосування WebView"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 055d9b8..ee06623 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ٹرانسکوڈنگ ڈیفالٹس کو اوور رائیڈ کریں"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ٹرانسکوڈنگ فعال کریں"</string>
     <string name="transcode_default" msgid="3784803084573509491">"فرض کریں کہ ایپس جدید فارمیٹس کو سپورٹ کرتی ہیں"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"ٹرانسکوڈنگ اطلاعات دکھائیں"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"چل رہی سروسز"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"فی الحال چل رہی سروسز دیکھیں اور انہیں کنٹرول کریں"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"‏WebView کا نفاذ"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index d897ba69..29c0f91 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Transkripsiya parametrlarini almashtirish"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Transkripsiyasini yoqish"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Ilovalarda zamonaviy kodlash formatlari ishlaydi deb hisoblash"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Transkripsiya bildirishnomalarini chiqarish"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Ishlab turgan ilovalar"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Ishlab turgan ilovalarni ko‘rish va boshqarish"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ta’minotchisi"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index c6b7915..39beecd 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Ghi đè tùy chọn chuyển mã mặc định"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Bật tính năng chuyển mã"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Giả định rằng các ứng dụng hỗ trợ định dạng hiện đại"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Hiển thị thông báo chuyển mã"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Các dịch vụ đang chạy"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Xem và kiểm soát các dịch vụ đang chạy"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Triển khai WebView"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 05b27d1..010a4dc 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"覆盖转码默认设置"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"启用转码"</string>
     <string name="transcode_default" msgid="3784803084573509491">"假设应用支持现代格式"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"显示转码通知"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"正在运行的服务"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"查看和控制当前正在运行的服务"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 实现"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 13398d7..1e06a91 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"覆寫轉碼預設設定"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"啟用轉碼功能"</string>
     <string name="transcode_default" msgid="3784803084573509491">"假設應用程式支援新型格式"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"顯示轉碼通知"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"執行中的服務"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"查看並控制目前正在執行中的服務"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 設置"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index fead5e5..2c077e7 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"覆寫轉碼預設設定"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"啟用轉碼"</string>
     <string name="transcode_default" msgid="3784803084573509491">"假設應用程式支援新格式"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"顯示轉碼通知"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"正在運作的服務"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"查看並管理目前正在執行的服務"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 實作"</string>
@@ -434,9 +435,9 @@
     <skip />
     <string name="power_discharge_by_enhanced" msgid="563438403581662942">"根據你的使用情形,目前電量為 <xliff:g id="LEVEL">%2$s</xliff:g>,預估可持續使用到<xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"根據你的使用情形,預估可持續使用到<xliff:g id="TIME">%1$s</xliff:g>"</string>
-    <string name="power_discharge_by" msgid="4113180890060388350">"目前電量 <xliff:g id="LEVEL">%2$s</xliff:g>,預估還能持續使用到<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="power_discharge_by" msgid="4113180890060388350">"目前電量 <xliff:g id="LEVEL">%2$s</xliff:g>,預估可用到<xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_discharge_by_only" msgid="92545648425937000">"預估電力大約可使用到<xliff:g id="TIME">%1$s</xliff:g>"</string>
-    <string name="power_discharge_by_only_short" msgid="5883041507426914446">"還能持續使用到<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="power_discharge_by_only_short" msgid="5883041507426914446">"可用到<xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"電池電力可能於<xliff:g id="TIME">%1$s</xliff:g> 前耗盡"</string>
     <string name="power_remaining_less_than_duration_only" msgid="8956656616031395152">"電池可用時間不到 <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
     <string name="power_remaining_less_than_duration" msgid="318215464914990578">"電池可用時間不到 <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 79b8946f1..87cf75b 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -404,6 +404,7 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Khipha okuzenzakalelayo kokudlulisela ikhodi"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Nika amandla ukudlulisela ikhodi"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Kuthathe njengokungathi izinhlelo zokusebenza zisekela amafomethi esimanje"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Bonisa izaziso zokudlulisela ikhodi"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Amasevisi asebenzayo"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Buka futhi ulawule amasevisi  asebenzayo okwamanje"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Ukufakwa ke-WebView"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java
index 228de03..35499c9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java
+++ b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java
@@ -80,7 +80,8 @@
      * Fills a list of applications which queried location recently within specified time.
      * Apps are sorted by recency. Apps with more recent location accesses are in the front.
      */
-    public List<Access> getAppList() {
+    @VisibleForTesting
+    List<Access> getAppList(boolean showSystemApps) {
         // Retrieve a location usage list from AppOps
         PackageManager pm = mContext.getPackageManager();
         AppOpsManager aoManager =
@@ -108,22 +109,26 @@
 
             // Don't show apps that do not have user sensitive location permissions
             boolean showApp = true;
-            for (int op : LOCATION_OPS) {
-                final String permission = AppOpsManager.opToPermission(op);
-                final int permissionFlags = pm.getPermissionFlags(permission, packageName, user);
-                if (PermissionChecker.checkPermissionForPreflight(mContext, permission,
-                        PermissionChecker.PID_UNKNOWN, uid, packageName)
-                                == PermissionChecker.PERMISSION_GRANTED) {
-                    if ((permissionFlags
-                            & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED) == 0) {
-                        showApp = false;
-                        break;
-                    }
-                } else {
-                    if ((permissionFlags
-                            & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED) == 0) {
-                        showApp = false;
-                        break;
+            if (!showSystemApps) {
+                for (int op : LOCATION_OPS) {
+                    final String permission = AppOpsManager.opToPermission(op);
+                    final int permissionFlags = pm.getPermissionFlags(permission, packageName,
+                            user);
+                    if (PermissionChecker.checkPermissionForPreflight(mContext, permission,
+                            PermissionChecker.PID_UNKNOWN, uid, packageName)
+                            == PermissionChecker.PERMISSION_GRANTED) {
+                        if ((permissionFlags
+                                & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED)
+                                == 0) {
+                            showApp = false;
+                            break;
+                        }
+                    } else {
+                        if ((permissionFlags
+                                & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED) == 0) {
+                            showApp = false;
+                            break;
+                        }
                     }
                 }
             }
@@ -137,8 +142,15 @@
         return accesses;
     }
 
-    public List<Access> getAppListSorted() {
-        List<Access> accesses = getAppList();
+
+    /**
+     * Gets a list of apps that accessed location recently, sorting by recency.
+     *
+     * @param showSystemApps whether includes system apps in the list.
+     * @return the list of apps that recently accessed location.
+     */
+    public List<Access> getAppListSorted(boolean showSystemApps) {
+        List<Access> accesses = getAppList(showSystemApps);
         // Sort the list of Access by recency. Most recent accesses first.
         Collections.sort(accesses, Collections.reverseOrder(new Comparator<Access>() {
             @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java b/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java
index ecd4066..f9584a3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java
@@ -38,6 +38,7 @@
 import android.os.UserManager;
 import android.provider.ContactsContract.DisplayPhoto;
 import android.provider.MediaStore;
+import android.util.EventLog;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.View;
@@ -126,6 +127,14 @@
         }
         final Uri pictureUri = data != null && data.getData() != null
                 ? data.getData() : mTakePictureUri;
+
+        // Check if the result is a content uri
+        if (!ContentResolver.SCHEME_CONTENT.equals(pictureUri.getScheme())) {
+            Log.e(TAG, "Invalid pictureUri scheme: " + pictureUri.getScheme());
+            EventLog.writeEvent(0x534e4554, "172939189", -1, pictureUri.getPath());
+            return false;
+        }
+
         switch (requestCode) {
             case REQUEST_CODE_CROP_PHOTO:
                 onPhotoCropped(pictureUri);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
index 245b7843..16d73a3 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
@@ -86,7 +86,7 @@
     @Test
     @Ignore
     public void testGetAppList_shouldFilterRecentAccesses() {
-        List<RecentLocationAccesses.Access> requests = mRecentLocationAccesses.getAppList();
+        List<RecentLocationAccesses.Access> requests = mRecentLocationAccesses.getAppList(false);
         // Only two of the apps have requested location within 15 min.
         assertThat(requests).hasSize(2);
         // Make sure apps are ordered by recency
@@ -115,7 +115,7 @@
         mockTestApplicationInfos(
                 Process.SYSTEM_UID, RecentLocationAccesses.ANDROID_SYSTEM_PACKAGE_NAME);
 
-        List<RecentLocationAccesses.Access> requests = mRecentLocationAccesses.getAppList();
+        List<RecentLocationAccesses.Access> requests = mRecentLocationAccesses.getAppList(true);
         // Android OS shouldn't show up in the list of apps.
         assertThat(requests).hasSize(2);
         // Make sure apps are ordered by recency
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index 66165b6..ad6a531 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -147,5 +147,10 @@
         VALIDATORS.put(Global.DEVELOPMENT_SETTINGS_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Global.NOTIFICATION_FEEDBACK_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Global.RESTRICTED_NETWORKING_MODE, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(
+                Global.ONE_HANDED_KEYGUARD_SIDE,
+                new InclusiveIntegerRangeValidator(
+                        /* first= */Global.ONE_HANDED_KEYGUARD_SIDE_LEFT,
+                        /* last= */Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT));
     }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 1ce738e..a0b9528 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -551,9 +551,6 @@
                 Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS,
                 GlobalSettingsProto.Development.FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS);
         dumpSetting(s, p,
-                Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM,
-                GlobalSettingsProto.Development.ENABLE_SIZECOMPAT_FREEFORM);
-        dumpSetting(s, p,
                 Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
                 GlobalSettingsProto.Development.ENABLE_NON_RESIZABLE_MULTI_WINDOW);
         p.end(developmentToken);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 664fd4a..4dc6d14 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -227,7 +227,6 @@
                     Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS,
                     Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES,
                     Settings.Global.DEVELOPMENT_FORCE_RTL,
-                    Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM,
                     Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
                     Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR,
                     Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_SV,
@@ -283,6 +282,7 @@
                     Settings.Global.EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS,
                     Settings.Global.EUICC_SWITCH_SLOT_TIMEOUT_MILLIS,
                     Settings.Global.FANCY_IME_ANIMATIONS,
+                    Settings.Global.ONE_HANDED_KEYGUARD_SIDE,
                     Settings.Global.FORCE_ALLOW_ON_EXTERNAL,
                     Settings.Global.FORCED_APP_STANDBY_ENABLED,
                     Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 2594840..1393116 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -84,8 +84,6 @@
     <uses-permission android:name="android.permission.READ_INPUT_STATE" />
     <uses-permission android:name="android.permission.SET_ORIENTATION" />
     <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
-    <!--  TODO(b/152310230): remove once APIs are confirmed to be sufficient -->
-    <uses-permission android:name="com.android.permission.USE_INSTALLER_V2" />
     <uses-permission android:name="com.android.permission.USE_SYSTEM_DATA_LOADERS" />
     <uses-permission android:name="android.permission.MOVE_PACKAGE" />
     <uses-permission android:name="android.permission.KEEP_UNINSTALLED_PACKAGES" />
@@ -125,6 +123,8 @@
     <uses-permission android:name="android.permission.MANAGE_CREDENTIAL_MANAGEMENT_APP" />
     <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
     <uses-permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS" />
+    <uses-permission android:name="android.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS" />
+    <uses-permission android:name="android.permission.CLEAR_FREEZE_PERIOD" />
     <uses-permission android:name="android.permission.QUERY_USERS" />
     <uses-permission android:name="android.permission.MODIFY_QUIET_MODE" />
     <uses-permission android:name="android.permission.ACCESS_LOWPAN_STATE"/>
@@ -164,6 +164,7 @@
     <uses-permission android:name="android.permission.MANAGE_APP_PREDICTIONS" />
     <uses-permission android:name="android.permission.MANAGE_SEARCH_UI" />
     <uses-permission android:name="android.permission.MANAGE_SMARTSPACE" />
+    <uses-permission android:name="android.permission.MANAGE_UI_TRANSLATION" />
     <uses-permission android:name="android.permission.NETWORK_SETTINGS" />
     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
     <uses-permission android:name="android.permission.SET_TIME" />
@@ -398,6 +399,7 @@
 
     <!-- Permission required for CTS to test sensor privacy behavior -->
     <uses-permission android:name="android.permission.MANAGE_SENSOR_PRIVACY" />
+    <uses-permission android:name="android.permission.OBSERVE_SENSOR_PRIVACY" />
 
     <!-- Permission needed for CTS test - CallLogTest -->
     <uses-permission android:name="com.android.voicemail.permission.READ_VOICEMAIL" />
diff --git a/packages/SoundPicker/res/layout-watch/add_new_sound_item.xml b/packages/SoundPicker/res/layout-watch/add_new_sound_item.xml
index 6f91d77..edfc0ab 100644
--- a/packages/SoundPicker/res/layout-watch/add_new_sound_item.xml
+++ b/packages/SoundPicker/res/layout-watch/add_new_sound_item.xml
@@ -20,6 +20,7 @@
      Make the visibility to "gone" to prevent failures.
  -->
 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/add_new_sound_text"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:minHeight="?android:attr/listPreferredItemHeightSmall"
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index fbe58c5..b6d942a 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -87,6 +87,7 @@
     <uses-permission android:name="android.permission.MASTER_CLEAR" />
     <uses-permission android:name="android.permission.VIBRATE" />
     <uses-permission android:name="android.permission.MANAGE_SENSOR_PRIVACY" />
+    <uses-permission android:name="android.permission.OBSERVE_SENSOR_PRIVACY" />
 
     <!-- ActivityManager -->
     <uses-permission android:name="android.permission.REAL_GET_TASKS" />
@@ -337,6 +338,7 @@
         <activity android:name=".screenshot.LongScreenshotActivity"
                   android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
                   android:process=":screenshot"
+                  android:exported="false"
                   android:finishOnTaskLaunch="true" />
 
         <activity android:name=".screenrecord.ScreenRecordDialog"
diff --git a/packages/SystemUI/README.md b/packages/SystemUI/README.md
index 60994d8..ee8d023 100644
--- a/packages/SystemUI/README.md
+++ b/packages/SystemUI/README.md
@@ -144,10 +144,6 @@
 
 Delegates SysUI events to WM Shell controllers.
 
-### [com.android.systemui.people.widget.PeopleSpaceWidgetEnabler](/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetEnabler.java)
-
-Enables People Space widgets.
-
 ---
 
  * [Plugins](/packages/SystemUI/docs/plugins.md)
diff --git a/packages/SystemUI/docs/media-controls-pipeline.png b/packages/SystemUI/docs/media-controls-pipeline.png
new file mode 100644
index 0000000..e7408ad
--- /dev/null
+++ b/packages/SystemUI/docs/media-controls-pipeline.png
Binary files differ
diff --git a/packages/SystemUI/docs/media-controls.md b/packages/SystemUI/docs/media-controls.md
new file mode 100644
index 0000000..579f453
--- /dev/null
+++ b/packages/SystemUI/docs/media-controls.md
@@ -0,0 +1,94 @@
+# SysUI Media Controls Pipeline
+
+[TOC]
+
+## Purpose
+
+Describe how events flow through the media controls pipeline, and provide a high level overview of what the different components do.
+
+## Pipeline Diagram
+
+![media controls pipeline](media-controls-pipeline.png)
+
+* Orange: External inputs
+* Blue: Internal listeners; all except `MediaDataManager` and `ResumeMediaBrowser` implement [`MediaDataManager.Listener`](/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt#711) and receive `onMediaDataLoaded` and `onMediaDataRemoved` events
+
+## Classes
+
+Files under [`systemui/media/`](/packages/SystemUI/src/com/android/systemui/media/):
+
+* UI
+   * `dialog/`
+      * Output switcher dialog (maintained by Settings team)
+   * IlluminationDrawable.kt
+   * LightSourceDrawable.kt
+      * These create the glow animation when you tap on a button (see [`qs_media_light_source`](/packages/SystemUI/res/drawable/qs_media_light_source.xml)). Should be reusable in other layouts.
+   * Carousel:
+      * MediaCarouselController.kt
+         * Keeps the carousel view up to date and handles state changes (e.g. expansion)
+         * Handles settings gear and page indicator
+      * MediaCarouselScrollHandler.kt
+         * Handles scrolling between players in the carousel
+      * MediaScrollView.kt
+         * Scrollview used in the carousel layout, has some custom measurement code
+   * Individual players:
+      * KeyguardMediaController.kt
+         * Lockscreen media controls have a special wrapper in order to work with the existing lockscreen notification layout
+      * MediaControlPanel.java
+         * Main class for media control UI
+      * SeekBarObserver.kt
+         * Updates seekbar state
+      * SeekBarViewModel.kt
+         * Implements its own `computePosition()` for the seekbar (to avoid continually polling the `PlaybackState`, which involves binder calls)
+         * Does some touch falsing (ignore flings, require drags to start near the thumb - otherwise users would often accidentally trigger the seekbar when they meant to move the carousel or shade)
+      * PlayerViewHolder.kt
+         * Holds references to the UI elements in the panel
+* Animation support:
+   * MediaHierarchyManager.kt
+      * Responsible for placement of media view and animation between hosts
+   * MediaHost.kt
+      * Every location that a media player could be located needs a `MediaHost`
+      * Tracks configuration (if it should show inactive media, needs falsing, etc.)
+   * MediaHostStatesManager.kt
+      * Manages the various media host states and coordinates heights between different players
+      * Has the most up to date state for any location
+   * MediaViewController.kt
+      * Controls a single instance of a media player, keeps the media view states up to date
+* Backend
+   * MediaData.kt
+      * Holds all the media data (track info, active/resume state, etc.)
+   * MediaDataCombineLatest.kt
+      * Combines update events from `MediaDataManager` and `MediaDeviceManager`, so that downstream listeners will have device info
+   * MediaDataFilter.kt
+      * Filters media data based on the current user
+      * Exit point for the pipeline: "external listeners" (currently `MediaHost` and `MediaCarouselController`), while they should be added via `MediaDataManager.addListener()`, will actually be listening to this output
+   * MediaDataManager.kt
+      * Entry point for the pipeline; initializes listener connections and assigns external listeners to the correct exit point
+      * Converts media notifications and resumable media info into `MediaData`
+   * MediaDeviceManager.kt
+      * Handles device updates
+   * MediaFeatureFlag.kt
+      * Utility to check whether media controls are enabled
+   * MediaSessionBasedFilter.kt
+      * Filters media events based on media session. This prevents duplicate controls in situations like casting where we might get both a local and remote object for the same media session.
+   * MediaTimeoutListener.kt
+      * Listens to `PlaybackState` and marks controls inactive after the media has been paused/stopped for 10 minutes (value can be adjusted locally with `adb shell setprop debug.sysui.media_timeout [ms]`)
+   * MediaResumeListener.kt
+      * Listens for new media data and attempts to find a valid `MediaBrowserService` for the app. If successful, sends the information back to the `MediaDataManager`
+      * Saves up to 5 valid `MediaBrowserService` components found this way, and queries them for recent media on boot or user change
+      * Note: the user can disable this feature completely (or block certain apps from being resumable) in [Settings](https://source.corp.google.com/android/packages/apps/Settings/src/com/android/settings/sound/ResumableMediaAppsController.java), in which case this listener will do nothing (or ignore updates from the blocked apps).
+   * ResumeMediaBrowser.java
+      * Connects to an app's [`MediaBrowser`](https://developer.android.com/reference/android/media/browse/MediaBrowser) to determine whether SystemUI is able to connect and find a recent [`MediaItem`](https://developer.android.com/reference/android/media/browse/MediaBrowser.MediaItem)
+* Factory classes (for unit testing):
+   * LocalMediaManagerFactory.kt
+   * MediaBrowserFactory.java
+   * MediaControllerFactory.java
+   * ResumeMediaBrowserFactory.java
+
+## Miscellaneous
+
+Other useful documents:
+
+* [go/sysui-media-resumption-requirements](https://goto.google.com/sysui-media-resumption-requirements) - Internal documentation for app developers about how to work with media resumption
+* [Playing nicely with media controls](https://android-developers.googleblog.com/2020/08/playing-nicely-with-media-controls.html) - blog post on the Android 11 updates
+* [Media Controls developer guide](https://developer.android.com/guide/topics/media/media-controls)
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java
index bcd28a6..53f7e44 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java
@@ -50,6 +50,4 @@
     public abstract void onStateChanged(State state);
 
     public abstract int getDetailY();
-
-    public void setShowLabels(boolean show) {}
 }
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml
index 7986809..71cdaf5 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml
@@ -24,7 +24,7 @@
     <include
         style="@style/BouncerSecurityContainer"
         layout="@layout/keyguard_host_view"
-        android:layout_width="wrap_content"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content" />
 </FrameLayout>
 
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml
index 04e645b..1e142ea 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml
@@ -41,13 +41,14 @@
         android:layout_gravity="center">
         <com.android.keyguard.KeyguardSecurityViewFlipper
             android:id="@+id/view_flipper"
-            android:layout_width="match_parent"
+            android:layout_width="wrap_content"
             android:layout_height="match_parent"
             android:clipChildren="false"
             android:clipToPadding="false"
             android:paddingTop="@dimen/keyguard_security_view_top_margin"
             android:paddingStart="@dimen/keyguard_security_view_lateral_margin"
             android:paddingEnd="@dimen/keyguard_security_view_lateral_margin"
+            android:layout_gravity="center"
             android:gravity="center">
         </com.android.keyguard.KeyguardSecurityViewFlipper>
     </com.android.keyguard.KeyguardSecurityContainer>
diff --git a/packages/SystemUI/res/layout/qs_tile_label_divider.xml b/packages/SystemUI/res-keyguard/values-sw600dp-land/bools.xml
similarity index 81%
rename from packages/SystemUI/res/layout/qs_tile_label_divider.xml
rename to packages/SystemUI/res-keyguard/values-sw600dp-land/bools.xml
index 150a5b8..e09bf7e 100644
--- a/packages/SystemUI/res/layout/qs_tile_label_divider.xml
+++ b/packages/SystemUI/res-keyguard/values-sw600dp-land/bools.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 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.
@@ -15,4 +15,6 @@
   ~ limitations under the License.
   -->
 
-<View />
\ No newline at end of file
+<resources>
+    <bool name="can_use_one_handed_bouncer">true</bool>
+</resources>
diff --git a/packages/SystemUI/res-keyguard/values/config.xml b/packages/SystemUI/res-keyguard/values/config.xml
index 8d9d6ee..6176f7c 100644
--- a/packages/SystemUI/res-keyguard/values/config.xml
+++ b/packages/SystemUI/res-keyguard/values/config.xml
@@ -22,4 +22,5 @@
 
     <!-- Allow the menu hard key to be disabled in LockScreen on some devices [DO NOT TRANSLATE] -->
     <bool name="config_disableMenuKeyInLockScreen">false</bool>
+    <bool name="can_use_one_handed_bouncer">false</bool>
 </resources>
diff --git a/packages/SystemUI/res-product/values-az/strings.xml b/packages/SystemUI/res-product/values-az/strings.xml
index ee86ae2..c0668db 100644
--- a/packages/SystemUI/res-product/values-az/strings.xml
+++ b/packages/SystemUI/res-product/values-az/strings.xml
@@ -38,8 +38,8 @@
     <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="3280816298678433681">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış cəhd etmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra iş profili silinəcək və bütün profil datası ləğv ediləcək."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4417100487251371559">"Planşetin kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhd etmisiniz. İş profili silinəcək və bütün data ləğv ediləcək."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhd etmisiniz. İş profili silinəcək və bütün data ləğv ediləcək."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Kilid açma modelini <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra planşet kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra yenidən cəhd edin."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Kilid açma modelini artıq <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra telefon kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra yenidən cəhd edin."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Kilid açma modelini <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra planşet kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra cəhd edin."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Kilid açma modelini artıq <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra telefon kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra cəhd edin."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Daha çox seçim üçün telefonu kiliddən çıxarın"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Daha çox seçim üçün planşeti kiliddən çıxarın"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Daha çox seçim üçün cihazı kiliddən çıxarın"</string>
diff --git a/packages/SystemUI/res/drawable/control_no_favorites_background.xml b/packages/SystemUI/res/drawable/control_no_favorites_background.xml
index d895dd0..2165b12 100644
--- a/packages/SystemUI/res/drawable/control_no_favorites_background.xml
+++ b/packages/SystemUI/res/drawable/control_no_favorites_background.xml
@@ -26,12 +26,4 @@
             <corners android:radius="@dimen/control_corner_radius" />
         </shape>
     </item>
-    <item>
-        <shape>
-            <stroke
-                android:width="1dp"
-                android:color="#4DFFFFFF" />
-            <corners android:radius="@dimen/control_corner_radius"/>
-        </shape>
-    </item>
 </ripple>
diff --git a/packages/SystemUI/res/drawable/controls_dialog_bg.xml b/packages/SystemUI/res/drawable/controls_dialog_bg.xml
index cb4686dd..1ccb176 100644
--- a/packages/SystemUI/res/drawable/controls_dialog_bg.xml
+++ b/packages/SystemUI/res/drawable/controls_dialog_bg.xml
@@ -16,6 +16,6 @@
 -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
-    <solid android:color="?android:attr/colorBackgroundFloating" />
+    <solid android:color="?android:attr/colorBackground" />
     <corners android:radius="@dimen/notification_corner_radius" />
 </shape>
diff --git a/packages/SystemUI/res/drawable/horizontal_ellipsis.xml b/packages/SystemUI/res/drawable/horizontal_ellipsis.xml
new file mode 100644
index 0000000..1800857
--- /dev/null
+++ b/packages/SystemUI/res/drawable/horizontal_ellipsis.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0"
+    android:tint="?android:attr/colorBackgroundFloating" >
+
+    <path
+        android:pathData="M6 10c-1.1 0-2 0.9-2 2s0.9 2 2 2 2-0.9 2-2-0.9-2-2-2zm12 0c-1.1 0-2 0.9-2 2s0.9 2 2 2 2-0.9 2-2-0.9-2-2-2zm-6 0c-1.1 0-2 0.9-2 2s0.9 2 2 2 2-0.9 2-2-0.9-2-2-2z"
+        android:fillColor="@android:color/white" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_open_in_new_fullscreen.xml b/packages/SystemUI/res/drawable/ic_open_in_new_fullscreen.xml
index 9f66581..96e0193 100644
--- a/packages/SystemUI/res/drawable/ic_open_in_new_fullscreen.xml
+++ b/packages/SystemUI/res/drawable/ic_open_in_new_fullscreen.xml
@@ -36,8 +36,4 @@
         </vector>
     </item>
 
-    <item>
-        <ripple android:color="@color/GM2_grey_600"></ripple>
-    </item>
-
 </layer-list>
diff --git a/packages/SystemUI/res/drawable/ic_open_in_new_window.xml b/packages/SystemUI/res/drawable/ic_open_in_new_window.xml
index 659b020..368c8df 100644
--- a/packages/SystemUI/res/drawable/ic_open_in_new_window.xml
+++ b/packages/SystemUI/res/drawable/ic_open_in_new_window.xml
@@ -50,28 +50,7 @@
                     android:strokeWidth="1"
                     android:pathData="M 12.5 13.92 L 15.59 17 L 17 15.59 L 13.91 12.5 L 16.5 12.5 L 16.5 10.5 L 10.5 10.5 L 10.5 16.5 L 12.5 16.5 Z" />
             </group>
-            <group
-                android:translateX="22.000000"
-                android:translateY="2.000000">
-                <group
-                    android:translateX="3.000000"
-                    android:translateY="3.000000">
-                    <group
-                        android:translateX="-3.000000"
-                        android:translateY="-3.000000">
-                        <path
-                            android:fillColor="#80868B"
-                            android:fillType="evenOdd"
-                            android:strokeWidth="1"
-                            android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-                    </group>
-                </group>
-            </group>
         </vector>
     </item>
 
-    <item>
-        <ripple android:color="@color/GM2_grey_600"></ripple>
-    </item>
-
 </layer-list>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view.xml b/packages/SystemUI/res/drawable/volume_drawer_bg.xml
similarity index 66%
copy from packages/SystemUI/res/layout/udfps_animation_view.xml
copy to packages/SystemUI/res/drawable/volume_drawer_bg.xml
index 380dd85..f0e2292 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view.xml
+++ b/packages/SystemUI/res/drawable/volume_drawer_bg.xml
@@ -14,8 +14,9 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/udfps_animation_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"/>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+            android:paddingMode="stack" >
+    <size android:width="@dimen/volume_ringer_drawer_item_size" />
+    <solid android:color="?android:attr/colorBackgroundFloating" />
+    <corners android:radius="@dimen/volume_ringer_drawer_item_size_half" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/udfps_animation_view.xml b/packages/SystemUI/res/drawable/volume_drawer_selection_bg.xml
similarity index 63%
copy from packages/SystemUI/res/layout/udfps_animation_view.xml
copy to packages/SystemUI/res/drawable/volume_drawer_selection_bg.xml
index 380dd85..5e7cb12 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view.xml
+++ b/packages/SystemUI/res/drawable/volume_drawer_selection_bg.xml
@@ -14,8 +14,11 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/udfps_animation_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"/>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+            android:paddingMode="stack" >
+    <size
+        android:height="@dimen/volume_ringer_drawer_item_size"
+        android:width="@dimen/volume_ringer_drawer_item_size" />
+    <solid android:color="?android:attr/colorAccent" />
+    <corners android:radius="@dimen/volume_ringer_drawer_item_size_half" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/volume_row_seekbar.xml b/packages/SystemUI/res/drawable/volume_row_seekbar.xml
new file mode 100644
index 0000000..b0e0ed5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/volume_row_seekbar.xml
@@ -0,0 +1,56 @@
+<?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.
+  -->
+
+<!-- SeekBar drawable for volume rows. This contains a background layer (with a solid round rect,
+     and a bottom-aligned icon) and a progress layer (with an accent-colored round rect and icon)
+     that moves up and down with the progress value. -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+            android:paddingMode="stack" >
+    <item android:id="@android:id/background"
+        android:gravity="center_vertical|fill_horizontal">
+        <layer-list>
+            <item android:id="@+id/volume_seekbar_background_solid">
+                <shape>
+                    <size android:height="@dimen/volume_dialog_panel_width" />
+                    <solid android:color="?android:attr/colorBackgroundFloating" />
+                    <corners android:radius="@dimen/volume_dialog_panel_width_half" />
+                </shape>
+            </item>
+            <item
+                android:id="@+id/volume_seekbar_background_icon"
+                android:gravity="center_vertical|left"
+                android:height="@dimen/rounded_slider_icon_size"
+                android:width="@dimen/rounded_slider_icon_size"
+                android:left="@dimen/rounded_slider_icon_inset">
+                <rotate
+                    android:fromDegrees="-270"
+                    android:toDegrees="-270">
+                    <!-- A placeholder drawable is required here - it'll be replaced in code. -->
+                    <com.android.systemui.util.AlphaTintDrawableWrapper
+                        android:drawable="@drawable/ic_volume_media"
+                        android:tint="?android:attr/colorAccent" />
+                </rotate>
+            </item>
+        </layer-list>
+    </item>
+    <item android:id="@android:id/progress"
+          android:gravity="center_vertical|fill_horizontal">
+            <com.android.systemui.util.RoundedCornerProgressDrawable
+                android:drawable="@drawable/volume_row_seekbar_progress"
+            />
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/volume_row_seekbar_progress.xml b/packages/SystemUI/res/drawable/volume_row_seekbar_progress.xml
new file mode 100644
index 0000000..ef20236
--- /dev/null
+++ b/packages/SystemUI/res/drawable/volume_row_seekbar_progress.xml
@@ -0,0 +1,44 @@
+<?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.
+  -->
+
+<!-- Progress drawable for volume row SeekBars. This is the accent-colored round rect that moves up
+     and down as the progress value changes. -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+    android:autoMirrored="true">
+    <item android:id="@+id/volume_seekbar_progress_solid">
+        <shape>
+            <size android:height="@dimen/volume_dialog_panel_width" />
+            <solid android:color="?android:attr/colorAccent" />
+            <corners android:radius="@dimen/volume_dialog_panel_width_half"/>
+        </shape>
+    </item>
+    <item
+        android:id="@+id/volume_seekbar_progress_icon"
+        android:gravity="center_vertical|right"
+        android:height="@dimen/rounded_slider_icon_size"
+        android:width="@dimen/rounded_slider_icon_size"
+        android:right="@dimen/rounded_slider_icon_inset">
+        <rotate
+            android:fromDegrees="-270"
+            android:toDegrees="-270">
+            <!-- A placeholder drawable is required here - it'll be replaced in code. -->
+            <com.android.systemui.util.AlphaTintDrawableWrapper
+                android:drawable="@drawable/ic_volume_media"
+                android:tint="?android:attr/colorBackgroundFloating" />
+        </rotate>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-land/volume_dialog.xml b/packages/SystemUI/res/layout-land/volume_dialog.xml
index c420117..237dc02 100644
--- a/packages/SystemUI/res/layout-land/volume_dialog.xml
+++ b/packages/SystemUI/res/layout-land/volume_dialog.xml
@@ -32,105 +32,124 @@
         android:gravity="right"
         android:layout_gravity="right"
         android:background="@android:color/transparent"
-        android:paddingRight="@dimen/volume_dialog_panel_transparent_padding_right"
-        android:paddingTop="@dimen/volume_dialog_panel_transparent_padding"
-        android:paddingBottom="@dimen/volume_dialog_panel_transparent_padding"
+        android:paddingRight="@dimen/volume_dialog_stream_padding"
         android:paddingLeft="@dimen/volume_dialog_panel_transparent_padding"
         android:clipToPadding="false">
 
-        <FrameLayout
-            android:id="@+id/ringer"
-            android:layout_width="@dimen/volume_dialog_ringer_size"
-            android:layout_height="@dimen/volume_dialog_ringer_size"
-            android:layout_marginBottom="@dimen/volume_dialog_spacer"
-            android:gravity="right"
-            android:layout_gravity="right"
-            android:translationZ="@dimen/volume_dialog_elevation"
-            android:clipToPadding="false"
-            android:background="@drawable/rounded_bg_full">
-            <com.android.keyguard.AlphaOptimizedImageButton
-                android:id="@+id/ringer_icon"
-                style="@style/VolumeButtons"
-                android:background="@drawable/rounded_ripple"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:scaleType="fitCenter"
-                android:padding="@dimen/volume_dialog_ringer_icon_padding"
-                android:tint="@color/accent_tint_color_selector"
-                android:layout_gravity="center"
-                android:soundEffectsEnabled="false" />
-
-            <include layout="@layout/volume_dnd_icon"
-                     android:layout_width="match_parent"
-                     android:layout_height="wrap_content"
-                     android:layout_marginRight="@dimen/volume_dialog_stream_padding"
-                     android:layout_marginTop="6dp"/>
-        </FrameLayout>
-
+        <!--
+            Container for a) the ringer drawer and the caption button next to b) the volume rows.
+        -->
         <LinearLayout
-            android:id="@+id/main"
             android:layout_width="wrap_content"
-            android:minWidth="@dimen/volume_dialog_panel_width"
             android:layout_height="wrap_content"
-            android:layout_marginTop="68dp"
-            android:gravity="right"
-            android:layout_gravity="right"
-            android:orientation="vertical"
-            android:translationZ="@dimen/volume_dialog_elevation"
+            android:orientation="horizontal"
             android:clipChildren="false"
-            android:clipToPadding="false"
-            android:background="@drawable/rounded_bg_full" >
-            <LinearLayout
-                android:id="@+id/volume_dialog_rows"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:minWidth="@dimen/volume_dialog_panel_width"
-                android:gravity="center"
-                android:orientation="horizontal"
-                android:paddingRight="@dimen/volume_dialog_stream_padding"
-                android:paddingLeft="@dimen/volume_dialog_stream_padding">
-                <!-- volume rows added and removed here! :-) -->
-            </LinearLayout>
-            <FrameLayout
-                android:id="@+id/settings_container"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:background="@drawable/rounded_bg_bottom_background">
-                <com.android.keyguard.AlphaOptimizedImageButton
-                    android:id="@+id/settings"
-                    android:src="@drawable/ic_tune_black_16dp"
-                    android:layout_width="@dimen/volume_dialog_tap_target_size"
-                    android:layout_height="@dimen/volume_dialog_tap_target_size"
-                    android:layout_gravity="center"
-                    android:contentDescription="@string/accessibility_volume_settings"
-                    android:background="@drawable/ripple_drawable_20dp"
-                    android:tint="?android:attr/textColorSecondary"
-                    android:soundEffectsEnabled="false" />
-            </FrameLayout>
-        </LinearLayout>
+            android:clipToPadding="false">
 
-        <FrameLayout
-            android:id="@+id/odi_captions"
-            android:layout_width="@dimen/volume_dialog_caption_size"
-            android:layout_height="@dimen/volume_dialog_caption_size"
-            android:layout_marginRight="68dp"
-            android:gravity="right"
-            android:layout_gravity="right"
-            android:clipToPadding="false"
-            android:translationZ="@dimen/volume_dialog_elevation"
-            android:background="@drawable/rounded_bg_full">
-            <com.android.systemui.volume.CaptionsToggleImageButton
-                android:id="@+id/odi_captions_icon"
-                android:src="@drawable/ic_volume_odi_captions_disabled"
-                style="@style/VolumeButtons"
-                android:background="@drawable/rounded_ripple"
-                android:layout_width="match_parent"
+            <!-- The ringer drawer and the caption button. -->
+            <FrameLayout
+                android:layout_width="wrap_content"
                 android:layout_height="match_parent"
-                android:tint="@color/caption_tint_color_selector"
-                android:layout_gravity="center"
-                android:soundEffectsEnabled="false"
-                sysui:optedOut="false"/>
-        </FrameLayout>
+                android:paddingRight="@dimen/volume_dialog_stream_padding"
+                android:clipChildren="false"
+                android:clipToPadding="false"
+                android:orientation="vertical">
+
+                <include layout="@layout/volume_ringer_drawer"
+                    android:layout_gravity="top|right"/>
+
+                <FrameLayout
+                    android:id="@+id/odi_captions"
+                    android:layout_width="@dimen/volume_dialog_caption_size"
+                    android:layout_height="@dimen/volume_dialog_caption_size"
+                    android:gravity="center"
+                    android:layout_gravity="bottom|right"
+                    android:layout_marginBottom="@dimen/volume_dialog_tap_target_size"
+                    android:clipToPadding="false">
+
+                    <com.android.systemui.volume.CaptionsToggleImageButton
+                        android:id="@+id/odi_captions_icon"
+                        android:src="@drawable/ic_volume_odi_captions_disabled"
+                        style="@style/VolumeButtons"
+                        android:background="@drawable/rounded_ripple"
+                        android:layout_width="match_parent"
+                        android:layout_height="match_parent"
+                        android:tint="@color/caption_tint_color_selector"
+                        android:layout_gravity="center"
+                        android:soundEffectsEnabled="false"
+                        sysui:optedOut="false"/>
+
+                </FrameLayout>
+
+            </FrameLayout>
+
+            <FrameLayout
+                android:visibility="gone"
+                android:id="@+id/ringer"
+                android:layout_width="@dimen/volume_dialog_ringer_size"
+                android:layout_height="@dimen/volume_dialog_ringer_size"
+                android:layout_marginBottom="@dimen/volume_dialog_spacer"
+                android:gravity="right"
+                android:layout_gravity="right"
+                android:translationZ="@dimen/volume_dialog_elevation"
+                android:clipToPadding="false"
+                android:background="@drawable/rounded_bg_full">
+                <com.android.keyguard.AlphaOptimizedImageButton
+                    android:id="@+id/ringer_icon"
+                    style="@style/VolumeButtons"
+                    android:background="@drawable/rounded_ripple"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:scaleType="fitCenter"
+                    android:padding="@dimen/volume_dialog_ringer_icon_padding"
+                    android:tint="@color/accent_tint_color_selector"
+                    android:layout_gravity="center"
+                    android:soundEffectsEnabled="false" />
+
+                <include layout="@layout/volume_dnd_icon"
+                         android:layout_width="match_parent"
+                         android:layout_height="wrap_content"
+                         android:layout_marginRight="@dimen/volume_dialog_stream_padding"
+                         android:layout_marginTop="6dp"/>
+            </FrameLayout>
+
+            <LinearLayout
+                android:id="@+id/main"
+                android:layout_width="wrap_content"
+                android:minWidth="@dimen/volume_dialog_panel_width"
+                android:layout_height="wrap_content"
+                android:gravity="right"
+                android:layout_gravity="right"
+                android:orientation="vertical"
+                android:clipChildren="false"
+                android:clipToPadding="false">
+                <LinearLayout
+                    android:id="@+id/volume_dialog_rows"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:minWidth="@dimen/volume_dialog_panel_width"
+                    android:gravity="center"
+                    android:orientation="horizontal">
+                    <!-- volume rows added and removed here! :-) -->
+                </LinearLayout>
+                <FrameLayout
+                    android:id="@+id/settings_container"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content">
+                    <com.android.keyguard.AlphaOptimizedImageButton
+                        android:id="@+id/settings"
+                        android:src="@drawable/horizontal_ellipsis"
+                        android:layout_width="@dimen/volume_dialog_tap_target_size"
+                        android:layout_height="@dimen/volume_dialog_tap_target_size"
+                        android:layout_gravity="center"
+                        android:contentDescription="@string/accessibility_volume_settings"
+                        android:background="@drawable/ripple_drawable_20dp"
+                        android:tint="?android:attr/colorBackgroundFloating"
+                        android:soundEffectsEnabled="false" />
+                </FrameLayout>
+            </LinearLayout>
+
+        </LinearLayout>
 
         <ViewStub
             android:id="@+id/odi_captions_tooltip_stub"
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 187ae58..cf9de5e 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -85,10 +85,10 @@
         android:tint="?attr/wallpaperTextColor" />
 
     <ImageView
-        android:id="@+id/alt_left_button"
+        android:id="@+id/wallet_button"
         android:layout_height="@dimen/keyguard_affordance_height"
         android:layout_width="@dimen/keyguard_affordance_width"
-        android:layout_gravity="bottom|start"
+        android:layout_gravity="bottom|end"
         android:scaleType="center"
         android:tint="?attr/wallpaperTextColor"
         android:layout_marginStart="24dp"
diff --git a/packages/SystemUI/res/layout/long_screenshot.xml b/packages/SystemUI/res/layout/long_screenshot.xml
index e2f3e2a..7ba28a8 100644
--- a/packages/SystemUI/res/layout/long_screenshot.xml
+++ b/packages/SystemUI/res/layout/long_screenshot.xml
@@ -76,7 +76,6 @@
         android:layout_height="wrap_content"
         android:layout_marginBottom="42dp"
         android:layout_marginHorizontal="48dp"
-        android:adjustViewBounds="true"
         app:layout_constrainedHeight="true"
         app:layout_constrainedWidth="true"
         app:layout_constraintTop_toBottomOf="@id/guideline"
@@ -110,6 +109,7 @@
         android:visibility="invisible"
         android:layout_width="200dp"
         android:layout_height="200dp"
+        android:elevation="2dp"
         app:layout_constraintTop_toBottomOf="@id/guideline"
         app:layout_constraintLeft_toLeftOf="parent"
         app:handleThickness="@dimen/screenshot_crop_handle_thickness"
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index 0822947..93dd1a1 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -81,6 +81,22 @@
             android:layout_height="match_parent"
             android:layout_weight="@integer/qs_footer_actions_weight"
             android:gravity="center_vertical|end" >
+
+            <com.android.systemui.statusbar.AlphaOptimizedImageView
+                android:id="@+id/pm_lite"
+                android:layout_width="@dimen/qs_footer_action_button_size"
+                android:layout_height="@dimen/qs_footer_action_button_size"
+                android:background="?android:attr/selectableItemBackgroundBorderless"
+                android:clickable="true"
+                android:clipToPadding="false"
+                android:contentDescription="@string/accessibility_quick_settings_edit"
+                android:focusable="true"
+                android:padding="@dimen/qs_footer_icon_padding"
+                android:src="@*android:drawable/ic_lock_power_off"
+                android:tint="?android:attr/colorForeground"
+                android:visibility="gone"
+                />
+
             <com.android.systemui.statusbar.phone.MultiUserSwitch
                 android:id="@+id/multi_user_switch"
                 android:layout_width="@dimen/qs_footer_action_button_size"
diff --git a/packages/SystemUI/res/layout/qs_paged_page_side_labels.xml b/packages/SystemUI/res/layout/qs_paged_page_side_labels.xml
index ee54f1d..c830773 100644
--- a/packages/SystemUI/res/layout/qs_paged_page_side_labels.xml
+++ b/packages/SystemUI/res/layout/qs_paged_page_side_labels.xml
@@ -14,4 +14,10 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<include layout="@layout/qs_paged_page" />
+<com.android.systemui.qs.SideLabelTileLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/tile_page"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:clipChildren="false"
+    android:clipToPadding="false" />
diff --git a/packages/SystemUI/res/layout/qs_tile_label.xml b/packages/SystemUI/res/layout/qs_tile_label.xml
index 571cbbc..1ce87c1 100644
--- a/packages/SystemUI/res/layout/qs_tile_label.xml
+++ b/packages/SystemUI/res/layout/qs_tile_label.xml
@@ -20,7 +20,6 @@
     android:layout_height="wrap_content"
     android:clipChildren="false"
     android:clipToPadding="false"
-    android:minHeight="48dp"
     android:paddingTop="12dp">
     <LinearLayout
         android:id="@+id/label_group"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 23f3425..bbb6107 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -37,12 +37,6 @@
         android:layout_height="match_parent"
         android:layout_width="match_parent" />
 
-    <ViewStub
-        android:id="@+id/keyguard_user_switcher_stub"
-        android:layout="@layout/keyguard_user_switcher"
-        android:layout_height="match_parent"
-        android:layout_width="match_parent" />
-
     <include
         layout="@layout/keyguard_status_view"
         android:visibility="gone" />
@@ -61,12 +55,14 @@
             android:id="@+id/qs_frame"
             android:layout="@layout/qs_panel"
             android:layout_width="@dimen/qs_panel_width"
-            android:layout_height="match_parent"
+            android:layout_height="0dp"
             android:clipToPadding="false"
             android:clipChildren="false"
             systemui:viewType="com.android.systemui.plugins.qs.QS"
             systemui:layout_constraintStart_toStartOf="parent"
             systemui:layout_constraintEnd_toEndOf="parent"
+            systemui:layout_constraintTop_toTopOf="parent"
+            systemui:layout_constraintBottom_toBottomOf="parent"
         />
 
         <androidx.constraintlayout.widget.Guideline
@@ -109,5 +105,11 @@
         layout="@layout/keyguard_bottom_area"
         android:visibility="gone" />
 
+    <ViewStub
+        android:id="@+id/keyguard_user_switcher_stub"
+        android:layout="@layout/keyguard_user_switcher"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent" />
+
     <include layout="@layout/status_bar_expanded_plugin_frame"/>
 </com.android.systemui.statusbar.phone.NotificationPanelView>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view_enroll.xml b/packages/SystemUI/res/layout/udfps_animation_view_enroll.xml
new file mode 100644
index 0000000..9b5752d
--- /dev/null
+++ b/packages/SystemUI/res/layout/udfps_animation_view_enroll.xml
@@ -0,0 +1,34 @@
+<?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.
+  -->
+<com.android.systemui.biometrics.UdfpsAnimationViewEnroll
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/udfps_animation_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <!-- Enrollment progress bar-->
+    <com.android.systemui.biometrics.UdfpsProgressBar
+        android:id="@+id/progress_bar"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:max="100"
+        android:padding="@dimen/udfps_enroll_progress_thickness"
+        android:progress="0"
+        android:layout_gravity="center"
+        android:visibility="gone"/>
+
+</com.android.systemui.biometrics.UdfpsAnimationViewEnroll>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view.xml b/packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml
similarity index 83%
rename from packages/SystemUI/res/layout/udfps_animation_view.xml
rename to packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml
index 380dd85..f32faa0 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view.xml
+++ b/packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml
@@ -14,8 +14,9 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationView
+<com.android.systemui.biometrics.UdfpsAnimationViewFpmOther
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/udfps_animation_view"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"/>
+    android:layout_height="match_parent">
+</com.android.systemui.biometrics.UdfpsAnimationViewFpmOther>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view.xml b/packages/SystemUI/res/layout/udfps_animation_view_keyguard.xml
similarity index 83%
copy from packages/SystemUI/res/layout/udfps_animation_view.xml
copy to packages/SystemUI/res/layout/udfps_animation_view_keyguard.xml
index 380dd85..644d1ada 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view.xml
+++ b/packages/SystemUI/res/layout/udfps_animation_view_keyguard.xml
@@ -14,8 +14,9 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.biometrics.UdfpsAnimationView
+<com.android.systemui.biometrics.UdfpsAnimationViewKeyguard
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/udfps_animation_view"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"/>
+    android:layout_height="match_parent">
+</com.android.systemui.biometrics.UdfpsAnimationViewKeyguard>
diff --git a/packages/SystemUI/res/layout/udfps_view.xml b/packages/SystemUI/res/layout/udfps_view.xml
index 6ae306e..e24c9e9 100644
--- a/packages/SystemUI/res/layout/udfps_view.xml
+++ b/packages/SystemUI/res/layout/udfps_view.xml
@@ -22,15 +22,10 @@
     android:layout_height="match_parent"
     systemui:sensorTouchAreaCoefficient="0.5">
 
-    <!-- Enrollment progress bar-->
-    <com.android.systemui.biometrics.UdfpsProgressBar
-        android:id="@+id/progress_bar"
+    <com.android.systemui.biometrics.UdfpsSurfaceView
+        android:id="@+id/hbm_view"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:max="100"
-        android:padding="@dimen/udfps_enroll_progress_thickness"
-        android:progress="0"
-        android:layout_gravity="center"
-        android:visibility="gone"/>
+        android:visibility="invisible"/>
 
 </com.android.systemui.biometrics.UdfpsView>
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 1810c19..6aac5a3 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -21,6 +21,8 @@
     android:layout_height="wrap_content"
     android:gravity="right"
     android:layout_gravity="right"
+    android:paddingRight="@dimen/volume_dialog_stream_padding"
+    android:clipToPadding="false"
     android:background="@android:color/transparent"
     android:theme="@style/volume_dialog_theme">
 
@@ -34,13 +36,15 @@
         android:layout_gravity="right"
         android:background="@android:color/transparent"
         android:paddingRight="@dimen/volume_dialog_panel_transparent_padding_right"
-        android:paddingTop="@dimen/volume_dialog_panel_transparent_padding"
-        android:paddingBottom="@dimen/volume_dialog_panel_transparent_padding"
         android:paddingLeft="@dimen/volume_dialog_panel_transparent_padding"
         android:orientation="vertical"
-        android:clipToPadding="false">
+        android:clipToPadding="false"
+        android:clipChildren="false">
+
+        <include layout="@layout/volume_ringer_drawer" />
 
         <FrameLayout
+            android:visibility="gone"
             android:id="@+id/ringer"
             android:layout_width="@dimen/volume_dialog_ringer_size"
             android:layout_height="@dimen/volume_dialog_ringer_size"
@@ -77,10 +81,8 @@
             android:gravity="right"
             android:layout_gravity="right"
             android:orientation="vertical"
-            android:translationZ="@dimen/volume_dialog_elevation"
             android:clipChildren="false"
-            android:clipToPadding="false"
-            android:background="@drawable/rounded_bg_full" >
+            android:clipToPadding="false" >
             <LinearLayout
                 android:id="@+id/volume_dialog_rows"
                 android:layout_width="wrap_content"
@@ -88,24 +90,22 @@
                 android:minWidth="@dimen/volume_dialog_panel_width"
                 android:gravity="center"
                 android:orientation="horizontal"
-                android:paddingRight="@dimen/volume_dialog_stream_padding"
-                android:paddingLeft="@dimen/volume_dialog_stream_padding">
+                android:layout_marginTop="@dimen/volume_row_slider_padding_start">
                     <!-- volume rows added and removed here! :-) -->
             </LinearLayout>
             <FrameLayout
                 android:id="@+id/settings_container"
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:background="@drawable/rounded_bg_bottom_background">
+                android:layout_height="wrap_content">
                 <com.android.keyguard.AlphaOptimizedImageButton
                     android:id="@+id/settings"
-                    android:src="@drawable/ic_tune_black_16dp"
+                    android:src="@drawable/horizontal_ellipsis"
                     android:layout_width="@dimen/volume_dialog_tap_target_size"
                     android:layout_height="@dimen/volume_dialog_tap_target_size"
                     android:layout_gravity="center"
                     android:contentDescription="@string/accessibility_volume_settings"
                     android:background="@drawable/ripple_drawable_20dp"
-                    android:tint="?android:attr/textColorPrimary"
+                    android:tint="?android:attr/colorBackgroundFloating"
                     android:soundEffectsEnabled="false" />
             </FrameLayout>
         </LinearLayout>
@@ -118,7 +118,6 @@
             android:gravity="right"
             android:layout_gravity="right"
             android:clipToPadding="false"
-            android:translationZ="@dimen/volume_dialog_elevation"
             android:background="@drawable/rounded_bg_full">
             <com.android.systemui.volume.CaptionsToggleImageButton
                 android:id="@+id/odi_captions_icon"
@@ -127,7 +126,7 @@
                 android:background="@drawable/rounded_ripple"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
-                android:tint="?android:attr/textColorPrimary"
+                android:tint="?android:attr/colorAccent"
                 android:layout_gravity="center"
                 android:soundEffectsEnabled="false"
                 sysui:optedOut="false"/>
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index b9efc5b..fda59b5 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -20,11 +20,12 @@
     android:layout_width="@dimen/volume_dialog_panel_width"
     android:clipChildren="false"
     android:clipToPadding="false"
+    android:translationZ="@dimen/volume_dialog_elevation"
     android:theme="@style/volume_dialog_theme">
 
     <LinearLayout
         android:layout_height="wrap_content"
-        android:layout_width="match_parent"
+        android:layout_width="@dimen/volume_dialog_panel_width"
         android:gravity="center"
         android:layout_gravity="center"
         android:orientation="vertical" >
@@ -41,21 +42,23 @@
         <FrameLayout
             android:id="@+id/volume_row_slider_frame"
             android:layout_width="match_parent"
-            android:layout_marginTop="@dimen/volume_dialog_slider_margin_top"
-            android:layout_marginBottom="@dimen/volume_dialog_slider_margin_bottom"
-            android:layoutDirection="rtl"
-            android:layout_height="@dimen/volume_dialog_slider_height">
+            android:layout_height="@dimen/volume_row_slider_height">
+            <include layout="@layout/volume_dnd_icon"/>
             <SeekBar
                 android:id="@+id/volume_row_slider"
+                android:paddingLeft="0dp"
+                android:paddingRight="0dp"
+                android:paddingStart="0dp"
+                android:paddingEnd="0dp"
                 android:clickable="true"
-                android:layout_width="@dimen/volume_dialog_slider_height"
+                android:layout_width="@dimen/volume_row_slider_height"
                 android:layout_height="match_parent"
-                android:layoutDirection="rtl"
                 android:layout_gravity="center"
-                android:rotation="90" />
+                android:rotation="270" />
         </FrameLayout>
 
         <com.android.keyguard.AlphaOptimizedImageButton
+            android:visibility="gone"
             android:id="@+id/volume_row_icon"
             style="@style/VolumeButtons"
             android:layout_width="@dimen/volume_dialog_tap_target_size"
@@ -66,6 +69,4 @@
             android:soundEffectsEnabled="false" />
     </LinearLayout>
 
-    <include layout="@layout/volume_dnd_icon"/>
-
 </FrameLayout>
diff --git a/packages/SystemUI/res/layout/volume_ringer_drawer.xml b/packages/SystemUI/res/layout/volume_ringer_drawer.xml
new file mode 100644
index 0000000..d6e1782
--- /dev/null
+++ b/packages/SystemUI/res/layout/volume_ringer_drawer.xml
@@ -0,0 +1,126 @@
+<?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.
+-->
+
+<!-- Contains the active ringer icon and a hidden drawer containing all three ringer options. -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:gravity="center"
+    android:clipToPadding="false"
+    android:clipChildren="false">
+
+    <!-- Drawer view, invisible by default. -->
+    <FrameLayout
+        android:id="@+id/volume_drawer_container"
+        android:alpha="0.0"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@drawable/volume_drawer_bg"
+        android:orientation="vertical">
+
+        <!-- View that is animated to a tapped ringer selection, so it appears selected. -->
+        <FrameLayout
+            android:id="@+id/volume_drawer_selection_background"
+            android:alpha="0.0"
+            android:layout_width="@dimen/volume_ringer_drawer_item_size"
+            android:layout_height="@dimen/volume_ringer_drawer_item_size"
+            android:layout_gravity="bottom|right"
+            android:background="@drawable/volume_drawer_selection_bg" />
+
+        <LinearLayout
+            android:id="@+id/volume_drawer_options"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <FrameLayout
+                android:id="@+id/volume_drawer_vibrate"
+                android:layout_width="@dimen/volume_ringer_drawer_item_size"
+                android:layout_height="@dimen/volume_ringer_drawer_item_size"
+                android:description="@string/volume_ringer_hint_vibrate"
+                android:gravity="center">
+
+                <ImageView
+                    android:id="@+id/volume_drawer_vibrate_icon"
+                    android:layout_width="@dimen/volume_ringer_drawer_icon_size"
+                    android:layout_height="@dimen/volume_ringer_drawer_icon_size"
+                    android:layout_gravity="center"
+                    android:tint="?android:attr/colorAccent"
+                    android:src="@drawable/ic_volume_ringer_vibrate" />
+
+            </FrameLayout>
+
+            <FrameLayout
+                android:id="@+id/volume_drawer_mute"
+                android:layout_width="@dimen/volume_ringer_drawer_item_size"
+                android:layout_height="@dimen/volume_ringer_drawer_item_size"
+                android:description="@string/volume_ringer_hint_mute"
+                android:gravity="center">
+
+                <ImageView
+                    android:id="@+id/volume_drawer_mute_icon"
+                    android:layout_width="@dimen/volume_ringer_drawer_icon_size"
+                    android:layout_height="@dimen/volume_ringer_drawer_icon_size"
+                    android:layout_gravity="center"
+                    android:tint="?android:attr/colorAccent"
+                    android:src="@drawable/ic_volume_ringer_mute" />
+
+            </FrameLayout>
+
+            <FrameLayout
+                android:id="@+id/volume_drawer_normal"
+                android:layout_width="@dimen/volume_ringer_drawer_item_size"
+                android:layout_height="@dimen/volume_ringer_drawer_item_size"
+                android:description="@string/volume_ringer_hint_unmute"
+                android:gravity="center">
+
+                <ImageView
+                    android:id="@+id/volume_drawer_normal_icon"
+                    android:layout_width="@dimen/volume_ringer_drawer_icon_size"
+                    android:layout_height="@dimen/volume_ringer_drawer_icon_size"
+                    android:layout_gravity="center"
+                    android:tint="?android:attr/colorAccent"
+                    android:src="@drawable/ic_volume_ringer" />
+
+            </FrameLayout>
+
+        </LinearLayout>
+
+    </FrameLayout>
+
+    <!-- The current ringer selection. When the drawer is opened, this animates to the corresponding
+         position in the drawer. When the drawer is closed, it animates back. -->
+    <FrameLayout
+        android:id="@+id/volume_new_ringer_active_icon_container"
+        android:layout_width="@dimen/volume_ringer_drawer_item_size"
+        android:layout_height="@dimen/volume_ringer_drawer_item_size"
+        android:layout_gravity="bottom|right"
+        android:description="@string/volume_ringer_change"
+        android:background="@drawable/volume_drawer_selection_bg">
+
+        <ImageView
+            android:id="@+id/volume_new_ringer_active_icon"
+            android:layout_width="@dimen/volume_ringer_drawer_icon_size"
+            android:layout_height="@dimen/volume_ringer_drawer_icon_size"
+            android:layout_gravity="center"
+            android:tint="?android:attr/colorBackgroundFloating"
+            android:src="@drawable/ic_volume_media" />
+
+    </FrameLayout>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 68c7467..c3a62b0 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Tot sonsopkoms"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aan om <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Tot <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Verminder helderheid"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is gedeaktiveer"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is geaktiveer"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ontsluit om NFC te gebruik"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Hierdie toestel behoort aan jou organisasie"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Hierdie toestel behoort aan <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Swiep vanaf ikoon vir foon"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Swiep vanaf ikoon vir stembystand"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Swiep vanaf ikoon vir kamera"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tik om te demp. Toeganklikheidsdienste kan dalk gedemp wees."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tik om op vibreer te stel."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tik om te demp."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"demp"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ontdemp"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibreer"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Voeg by"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Voorgestel deur <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontroles opgedateer"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Toestel is gesluit"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN bevat letters of simbole"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verifieer <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Verkeerde PIN"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 7618af8..0c0487d 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"ጸሐይ እስክትወጣ ድረስ"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> ላይ ይበራል"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"እስከ <xliff:g id="TIME">%s</xliff:g> ድረስ"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ብሩህነትን ይቀንሱ"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"ኤንኤፍሲ"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"ኤንኤፍሲ ተሰናክሏል"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"ኤንኤፍሲ ነቅቷል"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCን ለመጠቀም ይክፈቱ"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ይህ መሣሪያ የድርጅትዎ ነው"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"ይህ መሳሪያ ንብረትነቱ የ<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ነው"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ለስልክ ከአዶ ላይ ጠረግ ያድርጉ"</string>
     <string name="voice_hint" msgid="7476017460191291417">"ለድምጽ ረዳት ከአዶ ጠረግ ያድርጉ"</string>
     <string name="camera_hint" msgid="4519495795000658637">"ለካሜራ ከአዶ ላይ ጠረግ ያድርጉ"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s። ድምጸ-ከል ለማድረግ መታ ያድርጉ። የተደራሽነት አገልግሎቶች ድምጸ-ከል ሊደረግባቸው ይችላል።"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s። ወደ ንዝረት ለማቀናበር መታ ያድርጉ።"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s። ድምጸ-ከል ለማድረግ መታ ያድርጉ።"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ድምጸ-ከል አድርግ"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ድምጸ-ከልን አንሳ"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ንዘር"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"አክል"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"በ<xliff:g id="APP">%s</xliff:g> የተጠቆመ"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"መቆጣጠሪያዎች ተዘምነዋል"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"መሣሪያ ተቆልፏል"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ፒን ፊደሎችን ወይም ምልክቶችን ይይዛል"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> አረጋግጥ"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"የተሳሳተ ፒን"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 67622c7..ae8df90 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -420,7 +420,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"حتى شروق الشمس"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"تفعيل الوضع في <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"حتى <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"تقليل السطوع"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"تم إيقاف الاتصال القريب المدى"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"تم تفعيل الاتصال القريب المدى"</string>
@@ -454,6 +455,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"‏افتح قفل الشاشة لاستخدام تقنية NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"هذا الجهاز يخص مؤسستك."</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"هذا الجهاز يخص <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>."</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"يمكنك التمرير سريعًا من الرمز لتشغيل الهاتف"</string>
     <string name="voice_hint" msgid="7476017460191291417">"يمكنك التمرير سريعًا من الرمز لتشغيل المساعد الصوتي"</string>
     <string name="camera_hint" msgid="4519495795000658637">"يمكنك التمرير سريعًا من الرمز لتشغيل الكاميرا"</string>
@@ -637,6 +640,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"‏%1$s. انقر للتجاهل. قد يتم تجاهل خدمات \"سهولة الاستخدام\"."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"‏%1$s. انقر للتعيين على الاهتزاز."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"‏%1$s. انقر لكتم الصوت."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"كتم الصوت"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"إعادة الصوت"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"اهتزاز"</string>
@@ -1062,6 +1067,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"إضافة"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"اقتراح من <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"تم تعديل عناصر التحكّم."</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"الجهاز مُقفل."</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"يشتمل رقم التعريف الشخصي على أحرف أو رموز."</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"إثبات ملكية <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"رقم تعريف شخصي خاطئ"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index b1b28ad..1f92570 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"সূৰ্যোদয়লৈকে"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>ত অন কৰক"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> পৰ্যন্ত"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"উজ্জ্বলতা কমাওক"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC নিষ্ক্ৰিয় হৈ আছে"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC সক্ষম হৈ আছে"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ব্যৱহাৰ কৰিবলৈ আনলক কৰক"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"এই ডিভাইচটো আপোনাৰ প্ৰতিষ্ঠানৰ"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"এই ডিভাইচটো <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>ৰ"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ফ\'নৰ বাবে আইকনৰপৰা ছোৱাইপ কৰক"</string>
     <string name="voice_hint" msgid="7476017460191291417">"কণ্ঠধ্বনিৰে সহায়ৰ বাবে আইকনৰ পৰা ছোৱাইপ কৰক"</string>
     <string name="camera_hint" msgid="4519495795000658637">"কেমেৰা খুলিবলৈ আইকনৰপৰা ছোৱাইপ কৰক"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। মিউট কৰিবলৈ টিপক। দিব্য়াংগসকলৰ বাবে থকা সেৱা মিউট হৈ থাকিব পাৰে।"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। কম্পন অৱস্থাত ছেট কৰিবলৈ টিপক।"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। মিউট কৰিবলৈ টিপক।"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"মিউট কৰক"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"আনমিউট কৰক"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"কম্পন কৰক"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"যোগ দিয়ক"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g>এ পৰামৰ্শ হিচাপে আগবঢ়োৱা"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"নিয়ন্ত্ৰণসমূহ আপডে\'ট কৰা হৈছে"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"ডিভাইচ লক হৈ আছে"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"পিনত বৰ্ণ অথবা প্ৰতীকসমূহ থাকে"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> সত্যাপন কৰক"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"ভুল পিন"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index fed444b..e813a90 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Şəfəq vaxtına qədər"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Bu vaxt aktiv olur: <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Bu vaxtadək: <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Parlaqlığı Azaldın"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC deaktiv edilib"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC aktiv edilib"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC istifadə etmək üçün kiliddən çıxarın"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Bu cihaz təşkilatınıza məxsusdur"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Bu cihaz <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> təşkilatına məxsusdur"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Telefon üçün ikonadan sürüşdürün"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Səs yardımçısı üçün ikonadan sürüşdürün"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Kamera üçün ikonadan sürüşdürün"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Səssiz etmək üçün tıklayın. Əlçatımlılıq xidmətləri səssiz edilmiş ola bilər."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Vibrasiyanı ayarlamaq üçün klikləyin."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Səssiz etmək üçün klikləyin."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"susdurun"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"səssiz rejimdən çıxarın"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrasiya"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Əlavə edin"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> tərəfindən təklif edilib"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Nizamlayıcılar güncəlləndi"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Cihaz kilidlənib"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN hərflər və ya simvollar ehtiva edir"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> cihazını doğrulayın"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Yanlış PIN"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index ded8fa5..27d4b18 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -414,7 +414,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do izlaska sunca"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Uključuje se u <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Smanji osvetljenost"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je onemogućen"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je omogućen"</string>
@@ -448,6 +449,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da biste koristili NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Ovaj uređaj pripada organizaciji"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Ovaj uređaj pripada organizaciji <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Prevucite od ikone za telefon"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Prevucite od ikone za glasovnu pomoć"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Prevucite od ikone za kameru"</string>
@@ -628,6 +631,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dodirnite da biste isključili zvuk. Zvuk usluga pristupačnosti će možda biti isključen."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Dodirnite da biste podesili na vibraciju."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Dodirnite da biste isključili zvuk."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"isključite zvuk"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"uključite zvuk"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibracija"</string>
@@ -1044,6 +1049,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Predlaže <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrole su ažurirane"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Uređaj je zaključan"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN sadrži slova ili simbole"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verifikujte: <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Pogrešan PIN"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 18756f8..ab1cc69 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -416,7 +416,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Да ўсходу сонца"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Уключана ў <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Да <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Паменшыць яркасць"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC адключаны"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC уключаны"</string>
@@ -450,6 +451,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Разблакіруйце, каб выкарыстоўваць NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Гэта прылада належыць вашай арганізацыі"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Гэта прылада належыць арганізацыі \"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>\""</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Тэлефон: правядзіце пальцам ад значка"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Галасавая дапамога: правядзіце пальцам ад значка"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Камера: правядзіце пальцам ад значка"</string>
@@ -631,6 +634,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Дакраніцеся, каб адключыць гук. Можа быць адключаны гук службаў спецыяльных магчымасцей."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Дакраніцеся, каб уключыць вібрацыю."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Дакраніцеся, каб адключыць гук"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"выключыць гук"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"уключыць гук"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"вібрыраваць"</string>
@@ -1050,6 +1055,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Дадаць"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Прапанавана праграмай \"<xliff:g id="APP">%s</xliff:g>\""</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Элементы кіравання абноўлены"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Прылада блакіравана"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-код складаецца з літар або знакаў"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Спраўдзіце прыладу \"<xliff:g id="DEVICE">%s</xliff:g>\""</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Няправільны PIN-код"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index e1efd3b..6716e15 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"До изгрев"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ще се включи в <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"До <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Намаляване на яркостта"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"КБП е деактивирана"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"КБП е активирана"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Отключете, за да използвате NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Това устройство принадлежи на организацията ви"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Това устройство принадлежи на <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Плъзнете с пръст от иконата, за да използвате телефона"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Прекарайте пръст от иконата, за да получите гласова помощ"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Плъзнете с пръст от иконата, за да включите камерата"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Докоснете, за да заглушите звука. Възможно е звукът на услугите за достъпност да бъде заглушен."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Докоснете, за да зададете вибриране."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Докоснете, за да заглушите звука."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"спиране"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"пускане"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"вибриране"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Добавяне"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Предложено от <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Контролите са актуализирани"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"У-вото е заключено"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ПИН кодът съдържа букви или символи"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Потвърждаване на <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Грешен ПИН код"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 12f5345..ee639d6 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -93,10 +93,8 @@
     <string name="screenshot_scroll_description" msgid="7855773867093272175">"স্ক্রিনশট স্ক্রল করুন"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"স্ক্রিনশট বাতিল করুন"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"স্ক্রিনশটের প্রিভিউ"</string>
-    <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
-    <skip />
-    <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
-    <skip />
+    <string name="screenshot_top_boundary" msgid="1500569103321300856">"স্ক্রিনশটের একদম উপরের দিকে"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"স্ক্রিনশটের একদম নিচের দিকে"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"স্ক্রিন রেকর্ডার"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"স্ক্রিন রেকর্ডিং প্রসেস হচ্ছে"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"স্ক্রিন রেকর্ডিং সেশন চলার বিজ্ঞপ্তি"</string>
@@ -414,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"সূর্যোদয় পর্যন্ত"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>-এ চালু হবে"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> পর্যন্ত"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"উজ্জ্বলতা কমান"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC অক্ষম করা আছে"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC সক্ষম করা আছে"</string>
@@ -448,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ব্যবহার করতে আনলক করুন"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"এই ডিভাইসটি আপনার প্রতিষ্ঠানের"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"এই ডিভাইসটি <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>-এর"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ফোনের জন্য আইকন থেকে সোয়াইপ করুন"</string>
     <string name="voice_hint" msgid="7476017460191291417">"ভয়েস সহায়তার জন্য আইকন থেকে সোয়াইপ করুন"</string>
     <string name="camera_hint" msgid="4519495795000658637">"ক্যামেরার জন্য আইকন থেকে সোয়াইপ করুন"</string>
@@ -546,8 +547,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"আপনার প্রতিষ্ঠান আপনার অফিস প্রোফাইলে একটি সার্টিফিকেট কর্তৃপক্ষ ইনস্টল করেছে। আপনার নিরাপদ নেটওয়ার্ক ট্রাফিকে নজর রাখা হতে পারে বা তাতে পরিবর্তন করা হতে পারে।"</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"এই ডিভাইসে একটি সার্টিফিকেট কর্তৃপক্ষ ইনস্টল করা আছে। আপনার নিরাপদ নেটওয়ার্ক ট্রাফিকে নজর রাখা হতে পারে বা তাতে পরিবর্তন করা হতে পারে।"</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"আপনার প্রশাসক নেটওয়ার্ক লগিং চালু করেছেন, যা আপনার ডিভাইসের ট্রাফিকের উপরে নজর রাখে।"</string>
-    <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
-    <skip />
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"আপনার অ্যাডমিন নেটওয়ার্ক লগ করা চালু করেছেন যা আপনার অফিস প্রোফাইলে ট্রাফিক মনিটর করে তবে ব্যক্তিগত প্রোফাইলে করে না।"</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"আপনি <xliff:g id="VPN_APP">%1$s</xliff:g> এ সংযুক্ত রয়েছেন, যা আপনার ইমেল, অ্যাপ, এবং ওয়েবসাইট সহ আপনার নেটওয়ার্ক অ্যাক্টিভিটির উপর নজর রাখতে পারে।"</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"আপনি <xliff:g id="VPN_APP_0">%1$s</xliff:g> এবং <xliff:g id="VPN_APP_1">%2$s</xliff:g> এর সাথে সংযুক্ত রয়েছেন, যেগুলি আপনার ইমেল, অ্যাপ, এবং ওয়েবসাইট সহ আপনার নেটওয়ার্ক অ্যাক্টিভিটির উপর নজর রাখতে পারে।"</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"আপনার কর্মস্থলের প্রোফাইল <xliff:g id="VPN_APP">%1$s</xliff:g> এর সাথে সংযুক্ত রয়েছে, যেটি ইমেল, অ্যাপ, এবং ওয়েবসাইট সহ আপনার নেটওয়ার্ক কার্যকলাপে নজর রাখতে পারে।"</string>
@@ -628,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। মিউট করতে আলতো চাপুন। অ্যাক্সেসযোগ্যতার পরিষেবাগুলিকে মিউট করা হতে পারে।"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। ভাইব্রেট করতে ট্যাপ করুন।"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। মিউট করতে ট্যাপ করুন।"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"মিউট করুন"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"আনমিউট করুন"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ভাইব্রেট করান"</string>
@@ -1041,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"যোগ করুন"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> সাজেস্ট করেছে"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"কন্ট্রোল আপডেট করা হয়েছে"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"ডিভাইস লক করা আছে"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"পিন-এ অক্ষর বা চিহ্ন রয়েছে"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> যাচাই করুন"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"ভুল পিন"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 7463233..01a55d3 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -414,7 +414,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do svitanja"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Uključuje se u <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Smanji osvjetljenje"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je onemogućen"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je omogućen"</string>
@@ -448,6 +449,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da koristite NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Ovaj uređaj pripada vašoj organizaciji"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Ovaj uređaj pripada organizaciji <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Prevucite preko ikone da otvorite telefon"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Prevucite preko ikone za glasovnu pomoć"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Prevucite od ikone da otvorite kameru"</string>
@@ -628,6 +631,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dodirnite da isključite zvuk. Zvukovi usluga pristupačnosti mogu biti isključeni."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Dodirnite da postavite vibraciju."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Dodirnite da isključite zvuk."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"isključite zvuk"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"uključite zvuk"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibriranje"</string>
@@ -1044,6 +1049,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Predlaže <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrole su ažurirane"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Uređaj je zaključan"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN sadrži slova ili simbole"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Potvrdite uređaj <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Pogrešan PIN"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 524bb62..5d8ccbc 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Fins a l\'alba"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Activat a les <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Fins a les <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reducció de la brillantor"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"L\'NFC està desactivada"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"L\'NFC està activada"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloqueja per utilitzar l\'NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Aquest dispositiu pertany a la teva organització"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Aquest dispositiu pertany a <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Llisca des de la icona per obrir el telèfon"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Llisca des de la icona per obrir l\'assistent de veu"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Llisca des de la icona per obrir la càmera"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toca per silenciar el so. Pot ser que els serveis d\'accessibilitat se silenciïn."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toca per activar la vibració."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toca per silenciar."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"deixar de silenciar"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Afegeix"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Suggerit per <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"S\'han actualitzat els controls"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Dispositiu bloquejat"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"El PIN conté lletres o símbols"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verifica <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN incorrecte"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 47a673d..024b836 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -416,7 +416,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do svítání"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Zapnout v <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Snížit jas"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je vypnuto"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je zapnuto"</string>
@@ -450,6 +451,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC vyžaduje odemknutou obrazovku"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Toto zařízení patří vaší organizaci"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Toto zařízení patří organizaci <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Telefon otevřete přejetím prstem od ikony"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Hlasovou asistenci otevřete přejetím prstem od ikony"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Fotoaparát otevřete přejetím prstem od ikony"</string>
@@ -631,6 +634,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Klepnutím vypnete zvuk. Služby přístupnosti mohou být ztlumeny."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Klepnutím nastavíte vibrace."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Klepnutím vypnete zvuk."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"vypnout zvuk"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"zapnout zvuk"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrovat"</string>
@@ -1050,6 +1055,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Přidat"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Návrh z aplikace <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Ovládací prvky aktualizovány"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Zařízení uzamčeno"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Kód PIN obsahuje písmena nebo symboly"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Ověření zařízení <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Chybný PIN"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index e12b91c..b1a7a5a 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Indtil solopgang"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Tænd kl. <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Indtil kl. <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reducer lysstyrken"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC er deaktiveret"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC er aktiveret"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås op for at bruge NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Denne enhed tilhører din organisation"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Denne enhed tilhører <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Stryg fra telefonikonet"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Stryg fra mikrofonikonet"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Stryg fra kameraikonet"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tryk for at slå lyden fra. Lyden i tilgængelighedstjenester kan blive slået fra."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tryk for at aktivere vibration."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tryk for at slå lyden fra."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"slå lyden fra"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"slå lyden til"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrer"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Tilføj"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Foreslået af <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Betjeningselementerne er opdateret"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Enheden er låst"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Pinkoden indeholder bogstaver eller symboler"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Bekræft <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Forkert pinkode"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 6a69ed2..88dd62d 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -93,10 +93,8 @@
     <string name="screenshot_scroll_description" msgid="7855773867093272175">"Screenshot scrollen"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Screenshot schließen"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Screenshotvorschau"</string>
-    <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
-    <skip />
-    <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
-    <skip />
+    <string name="screenshot_top_boundary" msgid="1500569103321300856">"Oberer Rand"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Unterer Rand"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Bildschirmaufzeichnung"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Bildschirmaufzeichnung…"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Fortlaufende Benachrichtigung für eine Bildschirmaufzeichnung"</string>
@@ -414,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Bis Sonnenaufgang"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"An um <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Bis <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Helligkeit verringern"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ist deaktiviert"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ist aktiviert"</string>
@@ -448,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Zur Verwendung von NFC entsperren"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Dieses Gerät gehört deiner Organisation"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Dieses Gerät gehört <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Zum Öffnen des Telefons vom Symbol wegwischen"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Zum Öffnen des Sprachassistenten vom Symbol wegwischen"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Zum Öffnen der Kamera vom Symbol wegwischen"</string>
@@ -546,8 +547,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Deine Organisation hat ein Zertifikat einer Zertifizierungsstelle in deinem Arbeitsprofil installiert. Eventuell wird dein sicherer Netzwerkverkehr überwacht oder bearbeitet."</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"Auf dem Gerät ist das Zertifikat einer Zertifizierungsstelle installiert. Eventuell wird dein sicherer Netzwerkverkehr überwacht oder bearbeitet."</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"Dein Administrator hat die Netzwerkprotokollierung aktiviert. Damit wird der Netzwerkverkehr auf deinem Gerät überwacht."</string>
-    <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
-    <skip />
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"Dein Administrator hat die Netzwerkprotokollierung aktiviert. Damit werden die Zugriffe in deinem Arbeitsprofil erfasst, jedoch nicht in deinem privaten Profil."</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"Du bist mit <xliff:g id="VPN_APP">%1$s</xliff:g> verbunden. Die App kann deine Netzwerkaktivitäten (E-Mails, Apps und Websites) erfassen."</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"Du bist mit <xliff:g id="VPN_APP_0">%1$s</xliff:g> und <xliff:g id="VPN_APP_1">%2$s</xliff:g> verbunden. Die Apps können deine Netzwerkaktivitäten (E-Mails, Apps und Websites) erfassen."</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"Dein Arbeitsprofil ist mit <xliff:g id="VPN_APP">%1$s</xliff:g> verbunden, die deine Netzwerkaktivitäten wie E-Mails, Apps und Websites überwachen kann."</string>
@@ -628,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Zum Stummschalten tippen. Bedienungshilfen werden unter Umständen stummgeschaltet."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Zum Aktivieren der Vibration tippen."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Zum Stummschalten tippen."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"stummschalten"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"Stummschaltung aufheben"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrieren"</string>
@@ -1041,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Hinzufügen"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Vorgeschlagen von <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Gerätekarten aktualisiert"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Gerät gesperrt"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Die PIN enthält Buchstaben oder Symbole"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> bestätigen"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Falsche PIN"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 5bed0e5..2133025 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Μέχρι την ανατολή"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ενεργοποίηση στις <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Έως <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Μείωση φωτεινότητας"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"Το NFC είναι απενεργοποιημένο"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"Το NFC είναι ενεργοποιημένο"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ξεκλείδωμα για χρήση του NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Αυτή η συσκευή ανήκει στον οργανισμό σας."</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Αυτή η συσκευή ανήκει στον οργανισμό <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Σύρετε προς τα έξω για τηλέφωνο"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Σύρετε προς τα έξω για voice assist"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Σύρετε προς τα έξω για κάμερα"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Πατήστε για σίγαση. Οι υπηρεσίες προσβασιμότητας ενδέχεται να τεθούν σε σίγαση."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Πατήστε για να ενεργοποιήσετε τη δόνηση."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Πατήστε για σίγαση."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"σίγαση"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"κατάργηση σίγασης"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"δόνηση"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Προσθήκη"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Προτείνεται από <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Ενημέρωση στοιχείων ελέγχου"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Η συσκευή κλειδώθηκε"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Το PIN περιέχει γράμματα ή σύμβολα"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Επαλήθευση <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Λάθος PIN"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 137070f..0a0f8f7 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -412,7 +412,7 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Until sunrise"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"On at <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Until <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduce Brightness"</string>
+    <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Reduce brightness"</string>
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is disabled"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is enabled"</string>
@@ -446,6 +446,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"This device belongs to <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Swipe from icon for phone"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Swipe from icon for voice assist"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Swipe from icon for camera"</string>
@@ -625,6 +627,7 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tap to mute. Accessibility services may be muted."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tap to set to vibrate."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tap to mute."</string>
+    <string name="volume_ringer_change" msgid="3574969197796055532">"Tap to change ringer mode"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mute"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"unmute"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrate"</string>
@@ -1038,6 +1041,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Add"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Suggested by <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controls updated"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Device locked"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN contains letters or symbols"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verify <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Wrong PIN"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 5df29337..403fdee 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -412,7 +412,7 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Until sunrise"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"On at <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Until <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduce Brightness"</string>
+    <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Reduce brightness"</string>
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is disabled"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is enabled"</string>
@@ -446,6 +446,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"This device belongs to <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Swipe from icon for phone"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Swipe from icon for voice assist"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Swipe from icon for camera"</string>
@@ -625,6 +627,7 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tap to mute. Accessibility services may be muted."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tap to set to vibrate."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tap to mute."</string>
+    <string name="volume_ringer_change" msgid="3574969197796055532">"Tap to change ringer mode"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mute"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"unmute"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrate"</string>
@@ -1038,6 +1041,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Add"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Suggested by <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controls updated"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Device locked"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN contains letters or symbols"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verify <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Wrong PIN"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 137070f..0a0f8f7 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -412,7 +412,7 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Until sunrise"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"On at <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Until <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduce Brightness"</string>
+    <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Reduce brightness"</string>
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is disabled"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is enabled"</string>
@@ -446,6 +446,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"This device belongs to <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Swipe from icon for phone"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Swipe from icon for voice assist"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Swipe from icon for camera"</string>
@@ -625,6 +627,7 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tap to mute. Accessibility services may be muted."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tap to set to vibrate."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tap to mute."</string>
+    <string name="volume_ringer_change" msgid="3574969197796055532">"Tap to change ringer mode"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mute"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"unmute"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrate"</string>
@@ -1038,6 +1041,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Add"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Suggested by <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controls updated"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Device locked"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN contains letters or symbols"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verify <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Wrong PIN"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 137070f..0a0f8f7 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -412,7 +412,7 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Until sunrise"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"On at <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Until <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduce Brightness"</string>
+    <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Reduce brightness"</string>
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is disabled"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is enabled"</string>
@@ -446,6 +446,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"This device belongs to <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Swipe from icon for phone"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Swipe from icon for voice assist"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Swipe from icon for camera"</string>
@@ -625,6 +627,7 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tap to mute. Accessibility services may be muted."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tap to set to vibrate."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tap to mute."</string>
+    <string name="volume_ringer_change" msgid="3574969197796055532">"Tap to change ringer mode"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mute"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"unmute"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrate"</string>
@@ -1038,6 +1041,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Add"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Suggested by <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controls updated"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Device locked"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN contains letters or symbols"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verify <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Wrong PIN"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 46c09f6..a665fb1 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -412,7 +412,7 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‏‎‎‎‎‏‎‏‎‎‏‎‏‏‏‎‏‎‎‎‏‎‎‎‏‎‎‏‎‎‏‎‏‎‎‏‏‎‎‏‎‎‎‎‎‏‏‎‏‏‏‎‎‎‎Until sunrise‎‏‎‎‏‎"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‏‎‏‏‎‏‎‎‎‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‏‏‎‎‎‎‎‏‏‏‎‏‎‏‏‏‏‏‏‎On at ‎‏‎‎‏‏‎<xliff:g id="TIME">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‏‏‎‏‎‎‏‏‏‏‎‎‏‏‏‏‎‎‎‏‎‏‏‏‏‎‎‏‎‏‎‎‏‏‎‏‏‎‏‏‎‎‏‎‏‎‏‎Until ‎‏‎‎‏‏‎<xliff:g id="TIME">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‎‏‏‏‎‏‎‏‎‎‎‏‎‎‎‎‎‏‏‎‏‎‎‎‎‎‏‎‎‏‎‎‎‏‏‏‎‎‎‎‎‎‎‎‎‎‏‏‎‏‏‎‏‏‎Reduce Brightness‎‏‎‎‏‎"</string>
+    <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‏‎‎‎‎‎‏‏‎‏‏‏‎‎‏‎‎‎‎‏‎‏‏‏‎‎‏‏‎‎‎‏‏‎‎‏‏‎‏‏‏‏‎‏‏‎‎‏‏‏‎Reduce brightness‎‏‎‎‏‎"</string>
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‏‎‎‎‎‏‏‎‏‏‎‎‎‎‎‎‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‏‎‏‏‏‏‎‏‏‎‏‎‎‎‏‏‏‎‏‎‏‎‏‎NFC‎‏‎‎‏‎"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‎‎‎‏‎‏‏‎‎‎‏‎‎‏‏‏‎‎‏‏‎‎‎‏‏‏‏‎‎‎‏‎‏‎‎‎‎‏‎‏‎‎‎‎‎‏‎‏‏‎‎‏‎‏‏‏‎NFC is disabled‎‏‎‎‏‎"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‎‎‏‏‏‎‎‏‏‏‎‎‏‏‏‏‏‎‎‏‎‏‎‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‏‎‎NFC is enabled‎‏‎‎‏‎"</string>
@@ -446,6 +446,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‎‏‎‏‏‏‎‏‎‎‏‏‎‏‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‎‎‎‏‎‏‎‎‏‏‏‏‎Unlock to use NFC‎‏‎‎‏‎"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‏‎‏‎‎‏‎‏‏‏‏‎‎‎‏‎‏‎‎‏‎‎‏‏‎‏‎‏‏‎‎‏‎‏‏‏‏‎‏‏‏‏‏‎This device belongs to your organization‎‏‎‎‏‎"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‎‏‏‏‎‎‎‎‎‎‎‎‏‏‎‏‎‏‎‎‎‏‎‏‏‏‏‏‎‎‎‏‎‎‏‎‏‎‎‏‎‎‏‎‎‎‏‏‏‎‏‏‎This device belongs to ‎‏‎‎‏‏‎<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‏‎‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‏‏‏‏‎‎‎‎‏‏‏‏‎‏‎‎‎‎‎‏‎‎‎‏‏‎‏‏‎‏‏‎‏‎‏‎Swipe from icon for phone‎‏‎‎‏‎"</string>
     <string name="voice_hint" msgid="7476017460191291417">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‎‎‎‎‎‎‎‏‎‎‏‏‎‎‏‎‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‎‏‎‎‎‏‏‏‏‎‏‎‎‎‎‎‎‏‏‎‎‏‎Swipe from icon for voice assist‎‏‎‎‏‎"</string>
     <string name="camera_hint" msgid="4519495795000658637">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‏‏‏‎‏‎‏‏‏‏‎‎‎‎‏‏‏‎‎‎‏‎‏‏‎‎‏‎‏‎‏‏‎‎‏‏‎‏‎Swipe from icon for camera‎‏‎‎‏‎"</string>
@@ -625,6 +627,7 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‏‏‎‏‏‏‎‏‎‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‎‏‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‏‏‎‎‏‏‎‏‏‎‎‎‎%1$s. Tap to mute. Accessibility services may be muted.‎‏‎‎‏‎"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‎‎‏‏‏‎‏‎‏‏‎‏‏‎‏‎‏‎‎‏‏‏‎‏‎‏‏‎‎‎‏‎‏‏‎‏‏‏‎‎‎‏‎‎‏‏‎‏‎‏‏‏‏‏‎%1$s. Tap to set to vibrate.‎‏‎‎‏‎"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‎‏‏‏‎‏‏‏‎‏‎‎‏‎‎‎‏‎‎‏‎‏‎‏‏‎‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‏‏‎‎‎%1$s. Tap to mute.‎‏‎‎‏‎"</string>
+    <string name="volume_ringer_change" msgid="3574969197796055532">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‎‏‏‏‎‎‏‏‎‏‎‏‏‏‏‎‎‎‏‎‏‏‎‏‎‏‏‏‎‏‏‎‎‏‏‎‎‎‏‏‎‏‏‎‎‏‏‏‏‎‏‏‎‎‎Tap to change ringer mode‎‏‎‎‏‎"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‎‏‎‏‏‎‎‎‎‏‎‎‎‏‎‏‏‎‎‏‏‎‏‏‎‏‏‎‏‎‏‏‎‏‏‎‎‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‏‏‎‎mute‎‏‎‎‏‎"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‎‏‎‏‏‎‏‎‏‏‏‎‏‎‎‎‏‏‎‏‏‎‎‏‏‏‏‏‎‎‏‏‏‎‏‏‏‎‏‎‎‏‏‎‏‏‎‎‏‎‎‎‎‎unmute‎‏‎‎‏‎"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‏‎‏‎‎‎‎‎‏‎‎‎‏‏‎‎‎‎‏‎‎‏‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎‎‏‎‎‏‎‏‎vibrate‎‏‎‎‏‎"</string>
@@ -1038,6 +1041,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‏‎‎‎‏‏‏‎‏‎‏‎‏‏‎‎‎‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‏‎‎‎‏‎‏‎‎‏‏‎‏‏‏‏‎‎Add‎‏‎‎‏‎"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‏‎‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‎‎‏‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‏‏‏‎‎‏‎‏‎‎‏‎‏‎‏‎‎‏‎‎‎Suggested by ‎‏‎‎‏‏‎<xliff:g id="APP">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‎‏‎‎‎‏‏‏‎‏‏‏‎‏‎‎‏‏‎‎‎‎‏‎‎‎‏‏‏‎‎‎‎‏‏‎‏‏‏‎‎‎‏‏‎‎‏‎‎‎‏‎‏‏‏‎Controls updated‎‏‎‎‏‎"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‎‎‏‎‎‏‏‎‏‏‏‏‏‎‏‎‏‏‎‏‎‎‎‏‏‎‏‏‏‎‏‎‏‏‎‎‎‏‎‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎Device locked‎‏‎‎‏‎"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‎‎‏‎‎‏‏‏‎‏‎‎‏‎‎‏‎‎‏‏‎‎‎‏‎‎‏‏‏‏‏‎‎‏‎‎‏‎‎‎‎‏‎‏‏‎‏‏‏‏‎‎PIN contains letters or symbols‎‏‎‎‏‎"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‏‎‏‏‏‎‎‏‎‎‎‎‎‏‎‏‎‏‎‏‏‎‎‏‏‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‎‎Verify ‎‏‎‎‏‏‎<xliff:g id="DEVICE">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‎‎‏‏‎‎‏‎‎‏‎‎‏‏‎‎‏‎‏‏‏‏‎‏‏‎‏‎‏‏‏‎‎‏‏‎‏‏‏‏‎‏‏‏‏‏‏‏‏‎‎‏‏‎Wrong PIN‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index e1ad516..c97194f 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Hasta el amanecer"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"A la(s) <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Hasta la(s) <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reducir el brillo"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"La tecnología NFC está inhabilitada"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"La tecnología NFC está habilitada"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquea el dispositivo para usar NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertenece a tu organización"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertenece a <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Desliza el dedo para desbloquear el teléfono."</string>
     <string name="voice_hint" msgid="7476017460191291417">"Desliza el dedo desde el ícono para abrir asistente de voz."</string>
     <string name="camera_hint" msgid="4519495795000658637">"Desliza el dedo para acceder a la cámara."</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Presiona para silenciar. Es posible que los servicios de accesibilidad estén silenciados."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Presiona para establecer el modo vibración."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Presiona para silenciar."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"dejar de silenciar"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Agregar"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controles actualizados"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Dispos. bloqueado"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"El PIN contiene letras o símbolos"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verificar <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN incorrecto"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index c4b8b24..4c5ef0b 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Hasta el amanecer"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"A las <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Hasta las <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reducir brillo"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"El NFC está desactivado"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"El NFC está activado"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquea para usar el NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertenece a tu organización"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertenece a <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Desliza desde el icono para abrir el teléfono"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Desliza desde el icono para abrir asistente de voz"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Desliza desde el icono para abrir la cámara"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toca para silenciar. Los servicios de accesibilidad pueden silenciarse."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toca para activar la vibración."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toca para silenciar."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"dejar de silenciar"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Añadir"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controles actualizados"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Dispositivo bloqueado"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"El PIN contiene letras o símbolos"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verifica <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN incorrecto"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 5402b61..65c5930 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Kuni päikesetõusuni"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Sisse kell <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Kuni <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Ereduse vähendamine"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC on keelatud"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC on lubatud"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC kasutamiseks avage."</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"See seade kuulub teie organisatsioonile"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Selle seadme omanik on <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Telefoni kasutamiseks pühkige ikoonilt eemale"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Häälabi kasutamiseks pühkige ikoonilt eemale"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Kaamera kasutamiseks pühkige ikoonilt eemale"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Puudutage vaigistamiseks. Juurdepääsetavuse teenused võidakse vaigistada."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Puudutage vibreerimise määramiseks."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Puudutage vaigistamiseks."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"vaigistamine"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"vaigistuse tühistamine"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibreerimine"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Lisa"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Soovitas <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Juhtelemente värskendati"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Seade on lukustatud"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-kood sisaldab tähti või sümboleid"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Kinnitage <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Vale PIN-kood"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 510e7f9..9cebde1 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Egunsentira arte"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aktibatze-ordua: <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Desaktibatze-ordua: <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Murriztu distira"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"Desgaituta dago NFC"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"Gaituta dago NFC"</string>
@@ -443,9 +444,11 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Irekitzeko, ukitu berriro"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Pasatu hatza gora irekitzeko"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Berriro saiatzeko, pasatu hatza gora"</string>
-    <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desblokeatu NFC erabiltzeko"</string>
+    <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desblokea ezazu NFC erabiltzeko"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Gailu hau zure erakundearena da"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Gailu hau <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> erakundearena da"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Pasatu hatza ikonotik, telefonoa irekitzeko"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Pasatu hatza ikonotik, ahots-laguntza irekitzeko"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Pasatu hatza ikonotik, kamera irekitzeko"</string>
@@ -461,8 +464,8 @@
     <string name="keyguard_indication_charging_time_fast" msgid="7895986003578341126">"<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="245442950133408398">"<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 erabiltzailez. <xliff:g id="CURRENT_USER_NAME">%s</xliff:g> da saioa hasita duena."</string>
-    <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Uneko erabiltzailea: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</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>
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Erakutsi profila"</string>
     <string name="user_add_user" msgid="4336657383006913022">"Gehitu erabiltzailea"</string>
     <string name="user_new_user_name" msgid="2019166282704195789">"Erabiltzaile berria"</string>
@@ -478,7 +481,7 @@
     <string name="guest_notification_text" msgid="4202692942089571351">"Aplikazioak eta datuak ezabatzeko, kendu gonbidatua"</string>
     <string name="guest_notification_remove_action" msgid="4153019027696868099">"KENDU GONBIDATUA"</string>
     <string name="user_logout_notification_title" msgid="3644848998053832589">"Amaitu erabiltzailearen saioa"</string>
-    <string name="user_logout_notification_text" msgid="7441286737342997991">"Amaitu uneko erabiltzailearen saioa"</string>
+    <string name="user_logout_notification_text" msgid="7441286737342997991">"Amaitu erabiltzailearen saioa"</string>
     <string name="user_logout_notification_action" msgid="7974458760719361881">"AMAITU ERABILTZAILEAREN SAIOA"</string>
     <string name="user_add_user_title" msgid="4172327541504825032">"Beste erabiltzaile bat gehitu?"</string>
     <string name="user_add_user_message_short" msgid="2599370307878014791">"Erabiltzaile bat gehitzen duzunean, horrek bere eremua konfiguratu beharko du.\n\nEdozein erabiltzailek egunera ditzake beste erabiltzaile guztien aplikazioak."</string>
@@ -544,7 +547,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Erakundeak ziurtagiri-emaile bat instalatu dizu laneko profilean. Baliteke sareko trafiko segurua gainbegiratzea edo aldatzea."</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"Ziurtagiri-emaile bat dago instalatuta gailuan. Baliteke sareko trafiko segurua gainbegiratzea edo aldatzea."</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"Administratzaileak sare-erregistroak aktibatu ditu; horrela, zure gailuko trafikoa gainbegira dezake."</string>
-    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"Administratzaileak sare-erregistroak aktibatu ditu; horrela, zure laneko profileko trafikoa gainbegira dezake, baina ez zure profil pertsonalekoa."</string>
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"Administratzaileak sarearen erregistroak aktibatu ditu; horrela, zure laneko profileko trafikoa gainbegira dezake, baina ez zure profil pertsonalekoa."</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"<xliff:g id="VPN_APP">%1$s</xliff:g> aplikaziora konektatuta zaude eta hark sareko jarduerak gainbegira ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> eta <xliff:g id="VPN_APP_1">%2$s</xliff:g> aplikazioetara konektatuta zaude, eta haiek sareko jarduerak gainbegira ditzakete, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"<xliff:g id="VPN_APP">%1$s</xliff:g> aplikaziora dago konektatuta laneko profila, eta aplikazio horrek sareko jarduerak gainbegira ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Sakatu audioa desaktibatzeko. Baliteke erabilerraztasun-eginbideen audioa desaktibatzea."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Sakatu hau dardara ezartzeko."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Sakatu hau audioa desaktibatzeko."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"desaktibatu audioa"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"aktibatu audioa"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"dardara"</string>
@@ -954,7 +959,7 @@
     <string name="running_foreground_services_msg" msgid="3009459259222695385">"Sakatu bateria eta datuen erabilerari buruzko xehetasunak ikusteko"</string>
     <string name="mobile_data_disable_title" msgid="5366476131671617790">"Datu-konexioa desaktibatu nahi duzu?"</string>
     <string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g> erabilita ezingo dituzu erabili datuak edo Internet. Wifi-sare baten bidez soilik konektatu ahal izango zara Internetera."</string>
-    <string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"Uneko operadorea"</string>
+    <string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"Zure operadorea"</string>
     <string name="touch_filtered_warning" msgid="8119511393338714836">"Aplikazio bat baimen-eskaera oztopatzen ari denez, ezarpenek ezin dute egiaztatu erantzuna."</string>
     <string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_2">%2$s</xliff:g> aplikazioaren zatiak erakusteko baimena eman nahi diozu <xliff:g id="APP_0">%1$s</xliff:g> aplikazioari?"</string>
     <string name="slice_permission_text_1" msgid="6675965177075443714">"- <xliff:g id="APP">%1$s</xliff:g> aplikazioaren informazioa irakur dezake."</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Gehitu"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> aplikazioak iradoki du"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Eguneratu dira kontrolatzeko aukerak"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Gailua blokeatuta"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN kodeak hizkiak edo ikurrak ditu"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Egiaztatu <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN okerra"</string>
@@ -1049,8 +1055,8 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Pasatu hatza aukera gehiago ikusteko"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Gomendioak kargatzen"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Multimedia-edukia"</string>
-    <string name="controls_media_close_session" msgid="3957093425905475065">"Ezkutatu uneko saioa."</string>
-    <string name="controls_media_active_session" msgid="1984383994625845642">"Ezin da ezkutatu uneko saioa."</string>
+    <string name="controls_media_close_session" msgid="3957093425905475065">"Ezkutatu saioa."</string>
+    <string name="controls_media_active_session" msgid="1984383994625845642">"Ezin da ezkutatu saioa."</string>
     <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Baztertu"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Berrekin"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Ezarpenak"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 72d7b50..04b14f1 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"تا طلوع آفتاب"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"ساعت <xliff:g id="TIME">%s</xliff:g> روشن می‌شود"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"تا<xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"کاهش روشنایی"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"‏ارتباط میدان نزدیک (NFC)"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"‏«ارتباط میدان نزدیک» (NFC) غیرفعال است"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"‏«ارتباط میدان نزدیک» (NFC) فعال است"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"‏برای استفاده از NFC، قفل را باز کنید"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"این دستگاه به سازمان شما تعلق دارد"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"این دستگاه به <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> تعلق دارد"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"انگشتتان را از نماد تلفن تند بکشید"</string>
     <string name="voice_hint" msgid="7476017460191291417">"برای «دستیار صوتی»، تند بکشید"</string>
     <string name="camera_hint" msgid="4519495795000658637">"انگشتتان را از نماد دوربین تند بکشید"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"‏%1$s. برای صامت کردن ضربه بزنید. ممکن است سرویس‌های دسترس‌پذیری صامت شود."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"‏%1$s. برای تنظیم روی لرزش، ضربه بزنید."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"‏%1$s. برای صامت کردن ضربه بزنید."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"صامت کردن"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"باصدا کردن"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"لرزش"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"افزودن"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"پیشنهاد <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"کنترل‌ها به‌روزرسانی شد"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"دستگاه قفل است"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"پین شامل حروف یا نماد است"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"تأیید <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"پین اشتباه است"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 457d765..d08bfb5 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -125,7 +125,7 @@
     <string name="use_ptp_button_title" msgid="7676427598943446826">"Käytä kamerana (PTP)"</string>
     <string name="installer_cd_button_title" msgid="5499998592841984743">"Asenna Android File Transfer -sovellus Macille"</string>
     <string name="accessibility_back" msgid="6530104400086152611">"Takaisin"</string>
-    <string name="accessibility_home" msgid="5430449841237966217">"Aloituspainike"</string>
+    <string name="accessibility_home" msgid="5430449841237966217">"Aloitus"</string>
     <string name="accessibility_menu" msgid="2701163794470513040">"Valikko"</string>
     <string name="accessibility_accessibility_button" msgid="4089042473497107709">"Esteettömyys"</string>
     <string name="accessibility_rotate_button" msgid="1238584767612362586">"Näytön kääntäminen"</string>
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Auringonnousuun"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Päälle klo <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> asti"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Vähennä kirkkautta"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC on poistettu käytöstä"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC on käytössä"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Avaa lukitus, jotta voit käyttää NFC:tä"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Organisaatiosi omistaa tämän laitteen"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> omistaa tämän laitteen"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Avaa puhelu pyyhkäisemällä."</string>
     <string name="voice_hint" msgid="7476017460191291417">"Avaa ääniapuri pyyhkäisemällä kuvakkeesta."</string>
     <string name="camera_hint" msgid="4519495795000658637">"Avaa kamera pyyhkäisemällä."</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Mykistä koskettamalla. Myös esteettömyyspalvelut saattavat mykistyä."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Siirry värinätilaan napauttamalla."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Mykistä napauttamalla."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mykistä"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"poista mykistys"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"värinä"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Lisää"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Ehdottaja: <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Säätimet päivitetty"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Laite lukittu"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-koodi sisältää kirjaimia tai symboleja"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Vahvista <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Väärä PIN-koodi"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 3c4a9108..3d1ab93 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Jusqu\'à l\'aube"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Actif à <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Jusqu\'à <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Réduire la luminosité"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC désactivée"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC activée"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Déverrouillez l\'écran pour utiliser la NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Cet appareil appartient à votre organisation"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Cet appareil appartient à <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Balayez à partir de l\'icône pour accéder au téléphone"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Balayez à partir de l\'icône pour accéder à l\'assist. vocale"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Balayez à partir de l\'icône pour accéder à l\'appareil photo"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Touchez pour couper le son. Il est possible de couper le son des services d\'accessibilité."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Touchez pour activer les vibrations."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Touchez pour couper le son."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"désactiver le son"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"réactiver le son"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibration"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Ajouter"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Suggestion de <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Commandes mises à jour"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Appareil verrouillé"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Le NIP contient des lettres ou des symboles"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Vérifier <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"NIP incorrect"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 629cbba..c6d0674 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -238,7 +238,7 @@
     <skip />
     <string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notification masquée"</string>
     <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Volet des notifications"</string>
-    <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Paramètres rapides"</string>
+    <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Réglages rapides"</string>
     <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Écran de verrouillage"</string>
     <string name="accessibility_desc_settings" msgid="6728577365389151969">"Paramètres"</string>
     <string name="accessibility_desc_recent_apps" msgid="1748675199348914194">"Aperçu"</string>
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Jusqu\'à l\'aube"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"À partir de <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Jusqu\'à <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Réduire la luminosité"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC désactivée"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"La technologie NFC est activée"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Déverrouillez l\'écran pour pouvoir utiliser NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Cet appareil appartient à votre organisation"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Cet appareil appartient à <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Balayer pour téléphoner"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Balayer l\'écran depuis l\'icône pour l\'assistance vocale"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Balayer pour prendre une photo"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Appuyez pour ignorer. Vous pouvez ignorer les services d\'accessibilité."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Appuyez pour mettre en mode vibreur."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Appuyez pour ignorer."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"couper le son"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"réactiver le son"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"activer le vibreur"</string>
@@ -640,7 +645,7 @@
     <string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="6235377891802910455">"Afficher le pourcentage intégré de la batterie"</string>
     <string name="show_battery_percentage_summary" msgid="9053024758304102915">"Affichez le pourcentage correspondant au niveau de la batterie dans l\'icône de la barre d\'état lorsque l\'appareil n\'est pas en charge."</string>
-    <string name="quick_settings" msgid="6211774484997470203">"Configuration rapide"</string>
+    <string name="quick_settings" msgid="6211774484997470203">"Réglages rapides"</string>
     <string name="status_bar" msgid="4357390266055077437">"Barre d\'état"</string>
     <string name="overview" msgid="3522318590458536816">"Aperçu"</string>
     <string name="demo_mode" msgid="263484519766901593">"Mode de démonstration de l\'interface du système"</string>
@@ -650,13 +655,13 @@
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarme"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Profil professionnel"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Mode Avion"</string>
-    <string name="add_tile" msgid="6239678623873086686">"Ajouter une tuile"</string>
-    <string name="broadcast_tile" msgid="5224010633596487481">"Tuile de diffusion"</string>
+    <string name="add_tile" msgid="6239678623873086686">"Ajouter un bloc"</string>
+    <string name="broadcast_tile" msgid="5224010633596487481">"Bloc de diffusion"</string>
     <string name="zen_alarm_warning_indef" msgid="5252866591716504287">"Vous n\'entendrez pas votre prochaine alarme <xliff:g id="WHEN">%1$s</xliff:g>, sauf si vous désactivez cette option avant."</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Vous n\'entendrez pas votre prochaine alarme <xliff:g id="WHEN">%1$s</xliff:g>."</string>
     <string name="alarm_template" msgid="2234991538018805736">"à <xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="alarm_template_far" msgid="3561752195856839456">"le <xliff:g id="WHEN">%1$s</xliff:g>"</string>
-    <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Configuration rapide – <xliff:g id="TITLE">%s</xliff:g>"</string>
+    <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Réglages rapides – <xliff:g id="TITLE">%s</xliff:g>"</string>
     <string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Point d\'accès"</string>
     <string name="accessibility_managed_profile" msgid="4703836746209377356">"Profil professionnel"</string>
     <string name="tuner_warning_title" msgid="7721976098452135267">"Divertissant pour certains, mais pas pour tous"</string>
@@ -669,8 +674,8 @@
     <string name="activity_not_found" msgid="8711661533828200293">"L\'application n\'est pas installée sur votre appareil."</string>
     <string name="clock_seconds" msgid="8709189470828542071">"Afficher les secondes sur l\'horloge"</string>
     <string name="clock_seconds_desc" msgid="2415312788902144817">"Afficher les secondes dans la barre d\'état. Cela risque de réduire l\'autonomie de la batterie."</string>
-    <string name="qs_rearrange" msgid="484816665478662911">"Réorganiser la fenêtre de configuration rapide"</string>
-    <string name="show_brightness" msgid="6700267491672470007">"Afficher la luminosité dans fenêtre de configuration rapide"</string>
+    <string name="qs_rearrange" msgid="484816665478662911">"Réorganiser les Réglages rapides"</string>
+    <string name="show_brightness" msgid="6700267491672470007">"Afficher la luminosité dans les Réglages rapides"</string>
     <string name="experimental" msgid="3549865454812314826">"Paramètres expérimentaux"</string>
     <string name="enable_bluetooth_title" msgid="866883307336662596">"Activer le Bluetooth ?"</string>
     <string name="enable_bluetooth_message" msgid="6740938333772779717">"Pour connecter un clavier à votre tablette, vous devez avoir activé le Bluetooth."</string>
@@ -878,20 +883,20 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Afficher les icônes de notification à faible priorité"</string>
     <string name="other" msgid="429768510980739978">"Autre"</string>
-    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"supprimer la carte"</string>
-    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ajouter la carte à la fin"</string>
-    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Déplacer la carte"</string>
-    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Ajouter une carte"</string>
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"supprimer le bloc"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ajouter le bloc à la fin"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Déplacer le bloc"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Ajouter un bloc"</string>
     <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Déplacer vers <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Ajouter à la position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
-    <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Carte ajoutée"</string>
-    <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Carte supprimée"</string>
-    <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Éditeur de configuration rapide."</string>
+    <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Bloc ajouté"</string>
+    <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Bloc supprimé"</string>
+    <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Éditeur Réglages rapides"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notification <xliff:g id="ID_1">%1$s</xliff:g> : <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Ouvrir les paramètres."</string>
-    <string name="accessibility_quick_settings_expand" msgid="2609275052412521467">"Ouvrir la fenêtre de configuration rapide."</string>
-    <string name="accessibility_quick_settings_collapse" msgid="4674876336725041982">"Fermer la fenêtre de configuration rapide."</string>
+    <string name="accessibility_quick_settings_expand" msgid="2609275052412521467">"Ouvrir les Réglages rapides."</string>
+    <string name="accessibility_quick_settings_collapse" msgid="4674876336725041982">"Fermer les Réglages rapides."</string>
     <string name="accessibility_quick_settings_alarm_set" msgid="7237918261045099853">"Alarme définie."</string>
     <string name="accessibility_quick_settings_user" msgid="505821942882668619">"Connecté en tant que <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="data_connection_no_internet" msgid="691058178914184544">"Aucun accès à Internet"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Ajouter"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Suggérée par <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Commandes mises à jour"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Appareil verrouillé"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Le code contient des lettres ou des symboles"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Valider <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Code incorrect"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 9383fb6..08841a2 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Ata o amencer"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Activarase ás: <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Utilizarase ata as: <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reducir brillo"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"A opción NFC está desactivada"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"A opción NFC está activada"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquea o dispositivo para utilizar a NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence á túa organización"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertence a <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Pasa o dedo desde a icona para acceder ao teléfono"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Pasa o dedo desde a icona para acceder ao asistente de voz"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Pasa o dedo desde a icona para acceder á cámara"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toca para silenciar. Pódense silenciar os servizos de accesibilidade."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toca para establecer a vibración."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toca para silenciar."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"activar o son"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Engadir"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Control suxerido por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Actualizáronse os controis"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Disposit. bloqueado"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"O PIN contén letras ou símbolos"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verificar <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"O PIN é incorrecto"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index be62a29..867bc2f 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -93,10 +93,8 @@
     <string name="screenshot_scroll_description" msgid="7855773867093272175">"સ્ક્રીનશૉટ પર સ્ક્રોલ કરો"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"સ્ક્રીનશૉટ છોડી દો"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"સ્ક્રીનશૉટનો પ્રીવ્યૂ"</string>
-    <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
-    <skip />
-    <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
-    <skip />
+    <string name="screenshot_top_boundary" msgid="1500569103321300856">"સ્ક્રીનશૉટની સૌથી ઉપરની બાજુની સીમા"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"સ્ક્રીનશૉટની સૌથી નીચેની બાજુની સીમા"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"સ્ક્રીન રેકૉર્ડર"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"સ્ક્રીન રેકૉર્ડિંગ ચાલુ છે"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"સ્ક્રીન રેકોર્ડિંગ સત્ર માટે ચાલુ નોટિફિકેશન"</string>
@@ -414,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"સૂર્યોદય સુધી"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> વાગ્યે ચાલુ"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> વાગ્યા સુધી"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"બ્રાઇટનેસ ઘટાડો"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC અક્ષમ કરેલ છે"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC સક્ષમ કરેલ છે"</string>
@@ -448,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCનો ઉપયોગ કરવા માટે અનલૉક કરો"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"આ ડિવાઇસ તમારી સંસ્થાની માલિકીનું છે"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"આ ડિવાઇસ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>ની માલિકીનું છે"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ફોન માટે આયકનમાંથી સ્વાઇપ કરો"</string>
     <string name="voice_hint" msgid="7476017460191291417">"વૉઇસ સહાય માટે આયકનમાંથી સ્વાઇપ કરો"</string>
     <string name="camera_hint" msgid="4519495795000658637">"કૅમેરા માટે આયકનમાંથી સ્વાઇપ કરો"</string>
@@ -546,8 +547,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"તમારી સંસ્થાએ તમારી કાર્ય પ્રોફાઇલમાં પ્રમાણપત્ર સત્તાધિકારી ઇન્સ્ટૉલ કર્યું છે. તમારા સુરક્ષિત નેટવર્ક ટ્રાફિકનું નિયમન થઈ શકે છે અથવા તેમાં ફેરફાર કરવામાં આવી શકે છે."</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"આ ઉપકરણ પર પ્રમાણપત્ર સત્તાધિકારી ઇન્સ્ટૉલ કરેલ છે. તમારા સુરક્ષિત નેટવર્ક ટ્રાફિકનું નિયમન થઈ શકે છે અથવા તેમાં ફેરફાર કરવામાં આવી શકે છે."</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"તમારા વ્યવસ્થાપકે નેટવર્ક લૉગિંગ ચાલુ કર્યું છે, જે તમારા ઉપકરણ પર નેટવર્ક ટ્રાફિકનું નિયમન કરે છે."</string>
-    <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
-    <skip />
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"તમારા વ્યવસ્થાપકે નેટવર્ક લૉગ ઇન ચાલુ કર્યુ છે, જે તમારી વ્યક્તિગત પ્રોફાઇલમાં નહીં, પરંતુ ઑફિસની પ્રોફાઇલમાં ટ્રાફિકનું નિરીક્ષણ કરે છે."</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"તમે <xliff:g id="VPN_APP">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટ સહિત તમારી નેટવર્ક પ્રવૃત્તિનું નિરીક્ષણ કરી શકે છે."</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"તમે <xliff:g id="VPN_APP_0">%1$s</xliff:g> અને <xliff:g id="VPN_APP_1">%2$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટ સહિત તમારી નેટવર્ક પ્રવૃત્તિનું નિરીક્ષણ કરી શકે છે."</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"તમારી કાર્યાલયની પ્રોફાઇલ <xliff:g id="VPN_APP">%1$s</xliff:g> સાથે કનેક્ટ કરેલ છે, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટો સહિતની તમારી નેટવર્ક પ્રવૃત્તિનું નિયમન કરી શકે છે."</string>
@@ -628,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. મ્યૂટ કરવા માટે ટૅપ કરો. ઍક્સેસિબિલિટી સેવાઓ મ્યૂટ કરવામાં આવી શકે છે."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. કંપન પર સેટ કરવા માટે ટૅપ કરો."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. મ્યૂટ કરવા માટે ટૅપ કરો."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"મ્યૂટ કરો"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"અનમ્યૂટ કરો"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"વાઇબ્રેટ"</string>
@@ -1041,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"ઉમેરો"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> દ્વારા સૂચન કરેલા"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"નિયંત્રણ અપડેટ કર્યા"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"ડિવાઇસ લૉક કરેલું છે"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"પિનમાં અક્ષરો અથવા પ્રતીકોનો સમાવેશ થાય છે"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>ને ચકાસો"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"ખોટો પિન"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index b487689..a357ad2 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -93,8 +93,8 @@
     <string name="screenshot_scroll_description" msgid="7855773867093272175">"स्क्रीनशॉट को स्क्रोल करें"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"स्क्रीनशॉट को खारिज करें"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"स्क्रीनशॉट की झलक"</string>
-    <string name="screenshot_top_boundary" msgid="1500569103321300856">"स्क्रीनशाॉट की ऊपर की सीमा"</string>
-    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"स्क्रीनशॉट की नीचे की सीमा"</string>
+    <string name="screenshot_top_boundary" msgid="1500569103321300856">"स्क्रीनशॉट को ऊपर से काटने की सीमा"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"स्क्रीनशॉट को नीचे से काटने की सीमा"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"स्क्रीन रिकॉर्डर"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रीन रिकॉर्डिंग को प्रोसेस किया जा रहा है"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"स्क्रीन रिकॉर्ड सेशन के लिए जारी सूचना"</string>
@@ -414,7 +414,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"सुबह तक चालू रहेगी"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> पर चालू हाेगी"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> तक चालू रहेगी"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"स्क्रीन की चमक कम करें"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"एनएफ़सी"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC बंद है"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC चालू है"</string>
@@ -448,6 +449,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"एनएफ़सी इस्तेमाल करने के लिए स्क्रीन को अनलॉक करें"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"इस डिवाइस का मालिकाना हक आपके संगठन के पास है"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"इस डिवाइस का मालिकाना हक <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> के पास है"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"फ़ोन के लिए आइकॉन से स्वाइप करें"</string>
     <string name="voice_hint" msgid="7476017460191291417">"\'आवाज़ से डिवाइस का इस्तेमाल\' आइकॉन से स्वाइप करें"</string>
     <string name="camera_hint" msgid="4519495795000658637">"कैमरे के लिए आइकॉन से स्वाइप करें"</string>
@@ -546,7 +549,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"आपके संगठन ने आपकी वर्क प्रोफ़ाइल में एक प्रमाणपत्र अनुमति इंस्टॉल की है. आपके सुरक्षित नेटवर्क ट्रैफ़िक की निगरानी या उसमें बदलाव किया जा सकता है."</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"इस डिवाइस पर एक प्रमाणपत्र अनुमति इंस्टॉल की है. आपके सुरक्षित नेटवर्क ट्रैफ़िक की निगरानी या उसमें बदलाव किया जा सकता है."</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"आपके व्यवस्थापक ने नेटवर्क लॉगिंग चालू किया है, जो आपके डिवाइस पर ट्रैफ़िक की निगरानी करता है."</string>
-    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"आपके एडमिन ने नेटवर्क लॉगिंग की सुविधा चालू कर दी है, जिससे आपकी वर्क प्रोफ़ाइल पर आने वाले ट्रैफ़िक की निगरानी की जाती है. हालांकि, इससे आपकी निजी प्रोफ़ाइल की निगरानी नहीं की जाती."</string>
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"आपके एडमिन ने नेटवर्क लॉगिंग की सुविधा चालू कर दी है. इससे आपकी वर्क प्रोफ़ाइल पर आने वाले ट्रैफ़िक की निगरानी की जाती है. हालांकि, इससे आपकी निजी प्रोफ़ाइल की निगरानी नहीं की जाती."</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"आप <xliff:g id="VPN_APP">%1$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्लिकेशन और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकते हैं."</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"आप <xliff:g id="VPN_APP_0">%1$s</xliff:g> और <xliff:g id="VPN_APP_1">%2$s</xliff:g> से कनेक्ट हैं, जो ईमेल, ऐप्लिकेशन और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकते हैं."</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"आपकी वर्क प्रोफ़ाइल <xliff:g id="VPN_APP">%1$s</xliff:g> से कनेक्ट है, जो ईमेल, ऐप्लिकेशन और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
@@ -627,6 +630,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. म्यूट करने के लिए टैप करें. सुलभता सेवाएं म्यूट हो सकती हैं."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. कंपन (वाइब्रेशन) पर सेट करने के लिए छूएं."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. म्यूट करने के लिए टैप करें."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"म्यूट करें"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"अनम्यूट करें"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"वाइब्रेशन की सुविधा चालू करें"</string>
@@ -1040,6 +1045,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"जोड़ें"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> से मिला सुझाव"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"कंट्रोल अपडेट किए गए"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"डिवाइस लॉक है"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"पिन में अक्षर या चिह्न शामिल होते हैं"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> की पुष्टि करें"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"गलत पिन"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 8f3d7c0..d8064ab 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -414,7 +414,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do izlaska sunca"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Uključuje se u <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Smanjenje svjetline"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je onemogućen"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je omogućen"</string>
@@ -448,6 +449,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da biste upotrijebili NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Ovaj uređaj pripada vašoj organizaciji"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Ovaj uređaj pripada organizaciji <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Prijeđite prstom od ikone za telefon"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Prijeđite prstom od ikone za glasovnu pomoć"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Prijeđite prstom od ikone za fotoaparat"</string>
@@ -628,6 +631,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dodirnite da biste isključili zvuk. Usluge pristupačnosti možda neće imati zvuk."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Dodirnite da biste postavili na vibraciju."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Dodirnite da biste isključili zvuk."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"isključivanje zvuka"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"uključivanje zvuka"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibriranje"</string>
@@ -1044,6 +1049,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Preporuka s kanala <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrole su ažurirane"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Uređaj je zaključan"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN sadrži slova ili simbole"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Potvrdite uređaj <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Pogrešan PIN"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 4fda667..a736f88 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Napfelkeltéig"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Be: <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Eddig: <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Fényerő csökkentése"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"Az NFC ki van kapcsolva"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"Az NFC be van kapcsolva"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Az NFC használatához oldja fel a képernyőzárat"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Ez az eszköz az Ön szervezetének tulajdonában van"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Ez az eszköz a(z) <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> tulajdonában van"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"A telefonhoz csúsztasson az ikonról"</string>
     <string name="voice_hint" msgid="7476017460191291417">"A hangsegéd eléréséhez csúsztassa ujját az ikonról"</string>
     <string name="camera_hint" msgid="4519495795000658637">"A fényképezőhöz csúsztasson az ikonról"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Koppintson a némításhoz. Előfordulhat, hogy a kisegítő lehetőségek szolgáltatásai le vannak némítva."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Koppintson a rezgés beállításához."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Koppintson a némításhoz."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"némítás"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"némítás feloldása"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"rezgés"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Hozzáadás"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> javasolta"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Vezérlők frissítve"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Az eszköz zárolva van"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"A PIN-kód betűket vagy szimbólumokat tartalmaz"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ellenőrzése"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Helytelen PIN-kód"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index f0c1f21..40ddf54 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -412,7 +412,7 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Մինչև լուսաբաց"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Կմիանա՝ <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Մինչև <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Նվազեցնել պայծառությունը"</string>
+    <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Պայծառության նվազեցում"</string>
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC-ն անջատված է"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC-ն միացված է"</string>
@@ -446,6 +446,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ապակողպեք՝ NFC-ն օգտագործելու համար"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Այս սարքը պատկանում է ձեր կազմակերպությանը"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Այս սարքը պատկանում է «<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>» կազմակերպությանը"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Սահահարվածեք հեռախոսի պատկերակից"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Սահահարվածեք ձայնային հուշման պատկերակից"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Սահահարվածեք խցիկի պատկերակից"</string>
@@ -625,6 +627,7 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s: Հպեք՝ ձայնն անջատելու համար: Մատչելիության ծառայությունների ձայնը կարող է անջատվել:"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s։ Հպեք՝ թրթռոցը միացնելու համար։"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s։ Հպեք՝ ձայնը անջատելու համար։"</string>
+    <string name="volume_ringer_change" msgid="3574969197796055532">"Հպեք՝ զանգակի ռեժիմը փոխելու համար"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"անջատել ձայնը"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"միացնել ձայնը"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"միացնել թրթռոցը"</string>
@@ -1038,6 +1041,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Ավելացնել"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Առաջարկվել է <xliff:g id="APP">%s</xliff:g> հավելվածի կողմից"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Կառավարման տարրերը թարմացվեցին"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Սարքը կողպված է"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN կոդը տառեր և նշաններ է պարունակում"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Ստուգել <xliff:g id="DEVICE">%s</xliff:g> սարքը"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN կոդը սխալ է"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 71ff39c..e20dd51 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Sampai pagi"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aktif pada <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Sampai <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Kurangi Kecerahan"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC dinonaktifkan"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC diaktifkan"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Buka kunci untuk menggunakan NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Perangkat ini milik organisasi Anda"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Perangkat ini milik <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Geser dari ikon untuk telepon"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Geser dari ikon untuk bantuan suara"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Geser dari ikon untuk kamera"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ketuk untuk membisukan. Layanan aksesibilitas mungkin dibisukan."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Ketuk untuk menyetel agar bergetar."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Ketuk untuk menonaktifkan."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"Tanpa suara"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"aktifkan"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"getar"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Tambahkan"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Disarankan oleh <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrol diperbarui"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Perangkat terkunci"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN berisi huruf atau simbol"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verifikasi <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN salah"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 482338a..0c99420 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Til sólarupprásar"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Virkt kl. <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Til <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Draga úr birtu"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"Slökkt á NFC"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"Kveikt á NFC"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Taktu úr lás til að nota NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Þetta tæki tilheyrir fyrirtækinu þínu"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Þetta tæki tilheyrir <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Strjúktu frá tákninu fyrir síma"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Strjúktu frá tákninu fyrir raddaðstoð"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Strjúktu frá tákninu fyrir myndavél"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ýttu til að þagga. Hugsanlega verður slökkt á hljóði aðgengisþjónustu."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Ýttu til að stilla á titring."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Ýttu til að þagga."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"þagga"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"hætta að þagga"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"titringur"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Bæta við"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Tillaga frá <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Stýringar uppfærðar"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Tækið er læst"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN inniheldur bókstafi eða tákn"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Staðfesta <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Rangt PIN-númer"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 0896d0c..527a695 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Fino all\'alba"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Attivazione alle <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Fino alle <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Riduci la luminosità"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC non attiva"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC attiva"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Sblocca per usare NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Questo dispositivo appartiene alla tua organizzazione"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Questo dispositivo appartiene a <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Scorri per accedere al telefono"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Scorri dall\'icona per accedere a Voice Assist"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Scorri dall\'icona per accedere alla fotocamera"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tocca per disattivare l\'audio. L\'audio dei servizi di accessibilità può essere disattivato."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tocca per attivare la vibrazione."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tocca per disattivare l\'audio."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"disattiva l\'audio"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"riattiva l\'audio"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrazione"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Aggiungi"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Suggerito da <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controlli aggiornati"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Dispositivo bloccato"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Il PIN contiene lettere o simboli"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verifica <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN errato"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index e304dbe..9fc8b23 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -93,10 +93,8 @@
     <string name="screenshot_scroll_description" msgid="7855773867093272175">"צילום מסך נגלל"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"סגירת צילום מסך"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"תצוגה מקדימה של צילום מסך"</string>
-    <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
-    <skip />
-    <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
-    <skip />
+    <string name="screenshot_top_boundary" msgid="1500569103321300856">"הקצה העליון"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"הקצה התחתון"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"מקליט המסך"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"מתבצע עיבוד של הקלטת מסך"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"התראה מתמשכת לסשן הקלטת מסך"</string>
@@ -418,7 +416,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"עד הזריחה"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"יתחיל בשעה <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"עד <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"הפחתה של עוצמת הבהירות"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"‏NFC מושבת"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"‏NFC מופעל"</string>
@@ -452,6 +451,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"‏יש לבטל את הנעילה כדי להשתמש ב-NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"המכשיר הזה שייך לארגון שלך"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"המכשיר הזה שייך לארגון <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"החלק מהסמל כדי להפעיל את הטלפון"</string>
     <string name="voice_hint" msgid="7476017460191291417">"החלק מהסמל כדי להפעיל את המסייע הקולי"</string>
     <string name="camera_hint" msgid="4519495795000658637">"החלק מהסמל כדי להפעיל את המצלמה"</string>
@@ -552,8 +553,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"הארגון שלך התקין רשות אישורים בפרופיל העבודה. ניתן לעקוב אחר התנועה ברשת המאובטחת או לשנות אותה."</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"במכשיר זה מותקנת רשות אישורים. ניתן לעקוב אחר התנועה ברשת המאובטחת או לשנות אותה."</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"מנהל המערכת הפעיל את התכונה \'רישום התנועה ברשת\', שמנטרת את תנועת הנתונים במכשיר."</string>
-    <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
-    <skip />
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"מנהל המערכת הפעיל את תכונת רישום התנועה ברשת, שמנטרת את תנועת הנתונים בפרופיל העבודה, אבל לא בפרופיל האישי."</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"אתה מחובר לאפליקציה <xliff:g id="VPN_APP">%1$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת, כולל הודעות אימייל, אפליקציות ואתרים."</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"אתה מחובר לאפליקציות <xliff:g id="VPN_APP_0">%1$s</xliff:g> ו-<xliff:g id="VPN_APP_1">%2$s</xliff:g>, שיכולות לעקוב אחר הפעילות שלך ברשת, כולל הודעות אימייל, אפליקציות ואתרים."</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"פרופיל העבודה שלך מחובר לאפליקציה <xliff:g id="VPN_APP">%1$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת, כולל הודעות אימייל, אפליקציות ואתרים."</string>
@@ -634,6 +634,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"‏%1$s. הקש כדי להשתיק. ייתכן ששירותי הנגישות מושתקים."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"‏%1$s. הקש כדי להעביר למצב רטט."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"‏%1$s. הקש כדי להשתיק."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"השתקה"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ביטול ההשתקה"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"רטט"</string>
@@ -1053,6 +1055,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"הוספה"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"הוצע על-ידי <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"הפקדים עודכנו"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"המכשיר נעול"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"קוד האימות מכיל אותיות או סמלים"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"אימות <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"קוד גישה שגוי"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 05b1f76..1b18b5c 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"日の出まで"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>にオン"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g>まで"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"明るさを下げる"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC は無効です"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC は有効です"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC を使用するには、ロックを解除してください"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"これは組織が所有するデバイスです"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"これは <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> が所有するデバイスです"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"右にスワイプして通話"</string>
     <string name="voice_hint" msgid="7476017460191291417">"アイコンからスワイプして音声アシストを起動"</string>
     <string name="camera_hint" msgid="4519495795000658637">"左にスワイプしてカメラを起動"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s。タップしてミュートします。ユーザー補助機能サービスがミュートされる場合があります。"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s。タップしてバイブレーションに設定します。"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s。タップしてミュートします。"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ミュート"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ミュートを解除"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"バイブレーション"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"追加"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> によるおすすめ"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"コントロールを更新しました"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"デバイス: ロック状態"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN に英字や記号を含める"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>の確認"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN が間違っています"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 5404e67..e2b9fac 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"მზის ამოსვლამდე"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"ჩაირთოს <xliff:g id="TIME">%s</xliff:g>-ზე"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g>-მდე"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"სიკაშკაშის შემცირება"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC გათიშულია"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ჩართულია"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"განბლოკეთ NFC-ის გამოსაყენებლად"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ამ მოწყობილობას ფლობს თქვენი ორგანიზაცია"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"ამ მოწყობილობას ფლობს <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ტელეფონისთვის გადაფურცლეთ ხატულადან"</string>
     <string name="voice_hint" msgid="7476017460191291417">"ხმოვანი დახმარებისთვის გადაფურცლეთ ხატულადან"</string>
     <string name="camera_hint" msgid="4519495795000658637">"კამერისთვის გადაფურცლეთ ხატულადან"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. შეეხეთ დასადუმებლად. შეიძლება დადუმდეს მარტივი წვდომის სერვისებიც."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. შეეხეთ ვიბრაციაზე დასაყენებლად."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. შეეხეთ დასადუმებლად."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"დადუმება"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"დადუმების მოხსნა"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ვიბრაცია"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"დამატება"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"შემოთავაზებულია <xliff:g id="APP">%s</xliff:g>-ის მიერ"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"მართვის საშუალებები განახლდა"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"მოწყობილ. ჩაკეტილია"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-კოდი შეიცავს ასოებს ან სიმბოლოებს"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"დაადასტურეთ <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN-კოდი არასწორია"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 21c6201..1fbb8a5 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Күн шыққанға дейін"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Қосылу уақыты: <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> дейін"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Жарықтығын азайту"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC өшірулі"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC қосулы"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC пайдалану үшін құлыпты ашыңыз."</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Бұл құрылғы ұйымыңызға тиесілі."</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Бұл құрылғы <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ұйымына тиесілі."</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Телефонды ашу үшін белгішеден әрі қарай сырғытыңыз"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Дауыс көмекшісін ашу үшін белгішеден әрі қарай сырғытыңыз"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Камераны ашу үшін белгішеден әрі қарай сырғытыңыз"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Дыбысын өшіру үшін түртіңіз. Арнайы мүмкіндік қызметтерінің дыбысы өшуі мүмкін."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Діріл режимін орнату үшін түртіңіз."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Дыбысын өшіру үшін түртіңіз."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"дыбысын өшіру"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"дыбысын қосу"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"дірілдету"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Енгізу"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ұсынған"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Басқару элементтері жаңартылды"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Құрылғы құлыпталды."</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN коды әріптерден не таңбалардан құралады."</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> растау"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN коды қате"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 567bfa8..e6f9668 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"រហូត​ដល់​ពេល​ថ្ងៃរះ"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"បើកនៅម៉ោង <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"រហូតដល់ម៉ោង <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"បន្ថយពន្លឺ"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"បាន​បិទ NFC"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"បាន​បើក NFC"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"ដោះសោ ដើម្បីប្រើ NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ឧបករណ៍​នេះគឺជា​កម្មសិទ្ធិរបស់​ស្ថាប័ន​អ្នក"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"ឧបករណ៍នេះ​គឺជា​កម្មសិទ្ធិ​របស់ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"អូសចេញពីរូបតំណាងដើម្បីប្រើទូរស័ព្ទ"</string>
     <string name="voice_hint" msgid="7476017460191291417">"អូសចេញពីរូបតំណាងដើម្បីប្រើជំនួយសំឡេង"</string>
     <string name="camera_hint" msgid="4519495795000658637">"អូសចេញពីរូបតំណាងដើម្បីប្រើកាមេរ៉ា"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s។ ប៉ះដើម្បីបិទសំឡេង។ សេវាកម្មលទ្ធភាពប្រើប្រាស់អាចនឹងត្រូវបានបិទសំឡេង។"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s ។ ចុច​ដើម្បី​កំណត់​ឲ្យ​ញ័រ។"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s ។ ចុច​ដើម្បី​បិទ​សំឡេង។"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"បិទ​សំឡេង"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"បើក​សំឡេង"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ញ័រ"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"បញ្ចូល"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"បាន​ណែនាំដោយ <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"បានធ្វើបច្ចុប្បន្នភាពការគ្រប់គ្រង"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"បានចាក់សោ​ឧបករណ៍"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"កូដ PIN មាន​អក្សរ ឬនិមិត្តសញ្ញា"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"ផ្ទៀងផ្ទាត់ <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"កូដ PIN មិន​ត្រឹមត្រូវ​"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index e0ea3c2..15abcaa 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"ಸೂರ್ಯೋದಯದವರೆಗೆ"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> ಸಮಯದಲ್ಲಿ"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> ವರೆಗೂ"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ಪ್ರಖರತೆಯನ್ನು ಕಡಿಮೆ ಮಾಡಿ"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ನಿಷ್ಕ್ರಿಯಗೊಂಡಿದೆ"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ಸಕ್ರಿಯಗೊಂಡಿದೆ"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ಬಳಸಲು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ಈ ಸಾಧನವು ನಿಮ್ಮ ಸಂಸ್ಥೆಗೆ ಸೇರಿದೆ"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"ಈ ಸಾಧನವು <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ಗೆ ಸೇರಿದೆ"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ಫೋನ್‌ಗಾಗಿ ಐಕಾನ್‌ನಿಂದ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
     <string name="voice_hint" msgid="7476017460191291417">"ಧ್ವನಿ ಸಹಾಯಕ್ಕಾಗಿ ಐಕಾನ್‌ನಿಂದ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
     <string name="camera_hint" msgid="4519495795000658637">"ಕ್ಯಾಮರಾಗಾಗಿ ಐಕಾನ್‌ನಿಂದ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ಮ್ಯೂಟ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಪ್ರವೇಶಿಸುವಿಕೆ ಸೇವೆಗಳನ್ನು ಮ್ಯೂಟ್‌ ಮಾಡಬಹುದು."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. ವೈಬ್ರೇಟ್ ಮಾಡಲು ಹೊಂದಿಸುವುದಕ್ಕಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. ಮ್ಯೂಟ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ಮ್ಯೂಟ್ ಮಾಡಿ"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ಅನ್‌ಮ್ಯೂಟ್ ಮಾಡಿ"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ವೈಬ್ರೇಟ್‌"</string>
@@ -1038,6 +1043,8 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"ಸೇರಿಸಿ"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ಆ್ಯಪ್ ಸೂಚಿಸಿದೆ"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"ನಿಯಂತ್ರಣಗಳನ್ನು ನವೀಕರಿಸಲಾಗಿದೆ"</string>
+    <!-- no translation found for controls_tile_locked (731547768182831938) -->
+    <skip />
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ಪಿನ್ ಅಕ್ಷರಗಳು ಅಥವಾ ಸಂಕೇತಗಳನ್ನು ಒಳಗೊಂಡಿದೆ"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ಅನ್ನು ಪರಿಶೀಲಿಸಿ"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"ತಪ್ಪಾದ ಪಿನ್‌"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 64e4a69..78c2958 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"일출까지"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>에 켜짐"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g>까지"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"밝기 낮추기"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC 사용 중지됨"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC 사용 설정됨"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"잠금 해제하여 NFC 사용"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"내 조직에 속한 기기입니다."</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>에 속한 기기입니다."</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"전화 기능을 사용하려면 아이콘에서 스와이프하세요."</string>
     <string name="voice_hint" msgid="7476017460191291417">"음성 지원을 사용하려면 아이콘에서 스와이프하세요."</string>
     <string name="camera_hint" msgid="4519495795000658637">"카메라를 사용하려면 아이콘에서 스와이프하세요."</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. 탭하여 음소거로 설정하세요. 접근성 서비스가 음소거될 수 있습니다."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. 탭하여 진동으로 설정하세요."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. 탭하여 음소거로 설정하세요."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"음소거"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"음소거 해제"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"진동"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"추가"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g>에서 제안"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"컨트롤 업데이트됨"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"기기 잠김"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN에 문자나 기호가 포함됨"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> 확인"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"잘못된 PIN"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index ecbcd55..7a4d7d2 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -94,7 +94,7 @@
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Скриншотту четке кагуу"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Скриншотту алдын ала көрүү"</string>
     <string name="screenshot_top_boundary" msgid="1500569103321300856">"Жогорку чеги"</string>
-    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Баскычтын чеги"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Төмөнкү чеги"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"экрандан видео жаздырып алуу"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Экрандан жаздырылып алынган видео иштетилүүдө"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Экранды жаздыруу сеансы боюнча учурдагы билдирме"</string>
@@ -414,7 +414,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Күн чыкканга чейин"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Саат <xliff:g id="TIME">%s</xliff:g> күйөт"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> чейин"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Экрандын жарыктыгын төмөндөтүү"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC өчүрүлгөн"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC иштетилген"</string>
@@ -448,6 +449,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC колдонуу үчүн түзмөктүн кулпусун ачыңыз"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Бул түзмөк уюмуңузга таандык"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Бул түзмөк төмөнкүгө таандык: <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Сүрөтчөнү сүрүп телефонго өтүңүз"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Сүрөтчөнү сүрүп үн жардамчысына өтүңүз"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Сүрөтчөнү сүрүп камерага өтүңүз"</string>
@@ -627,6 +630,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Үнүн өчүрүү үчүн таптап коюңуз. Атайын мүмкүнчүлүктөр кызматынын үнүн өчүрүп койсо болот."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Дирилдөөгө коюу үчүн басыңыз."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Үнүн өчүрүү үчүн басыңыз."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"үнсүз"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"үнүн чыгаруу"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"дирилдөө"</string>
@@ -1040,6 +1045,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Кошуу"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> сунуштайт"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Башкаруу элементтери жаңырды"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Түзмөк кулпуланды"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN код тамгалардан же символдордон турат"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> түзмөгүн ырастаңыз"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN код туура эмес"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 98a75c2..7070fa1 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"ຈົນກວ່າຕາເວັນຂຶ້ນ"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"ເປີດເວລາ <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"ຈົນຮອດ <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ຫຼຸດຄວາມສະຫວ່າງ"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is disabled"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is enabled"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"ປົດລັອກເພື່ອໃຊ້ NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ອຸປະກອນນີ້ເປັນຂອງອົງການທ່ານ"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"ອຸ​ປະ​ກອນ​ນີ້​ເປັນ​ຂອງ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ປັດ​ຈາກ​ໄອ​ຄອນ​ສຳ​ລັບ​ໂທ​ລະ​ສັບ"</string>
     <string name="voice_hint" msgid="7476017460191291417">"ປັດ​ຈາກ​ໄອ​ຄອນ​ສຳ​ລັບ​ການ​ຊ່ວຍ​ທາງ​ສຽງ"</string>
     <string name="camera_hint" msgid="4519495795000658637">"ປັດ​ຈາກ​ໄອ​ຄອນ​ສຳ​ລັບ​ກ້ອງ​ຖ່າຍ​ຮູບ"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ແຕະເພື່ອປິດສຽງ. ບໍລິການຊ່ວຍເຂົ້າເຖິງອາດຖືກປິດສຽງໄວ້."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. ແຕະເພື່ອຕັ້ງເປັນສັ່ນເຕືອນ."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. ແຕະເພື່ອປິດສຽງ."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ປິດສຽງ"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ເຊົາປິດສຽງ"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ສັ່ນເຕືອນ"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"ເພີ່ມ"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"ແນະນຳໂດຍ <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"ອັບເດດການຄວບຄຸມແລ້ວ"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"ອຸປະກອນຖືກລັອກໄວ້"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN ປະກອບມີຕົວອັກສອນ ຫຼື ສັນຍາລັກ"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"ຢັ້ງຢືນ <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN ບໍ່ຖືກຕ້ອງ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index f4a2a0d..ff69e05 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -416,7 +416,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Iki saulėtekio"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Iki <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Šviesumo mažinimas"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"ALR"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"ALR išjungtas"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"ALR įjungtas"</string>
@@ -450,6 +451,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Norėdami naudoti NFC, atrakinkite"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Šis įrenginys priklauso jūsų organizacijai"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Šis įrenginys priklauso „<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>“"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Perbraukite iš telefono piktogramos"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Perbraukite iš „Voice Assist“ piktogramos"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Perbraukite iš fotoaparato piktogramos"</string>
@@ -631,6 +634,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Palieskite, kad nutildytumėte. Gali būti nutildytos pritaikymo neįgaliesiems paslaugos."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Palieskite, kad nustatytumėte vibravimą."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Palieskite, kad nutildytumėte."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"nutildyti"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"įjungti garsą"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibruoti"</string>
@@ -1050,6 +1055,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Pridėti"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Siūlo „<xliff:g id="APP">%s</xliff:g>“"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Valdikliai atnaujinti"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Įrenginys užrakintas"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN kodą sudaro raidės arba simboliai"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> patvirtinimas"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Netinkamas PIN kodas"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index caca22c..18816ad 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -414,7 +414,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Līdz saullēktam"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Plkst. <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Līdz plkst. <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Spilgtuma samazināšana"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ir atspējoti"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ir iespējoti"</string>
@@ -448,6 +449,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Atbloķējiet ierīci, lai izmantotu NFC."</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Šī ierīce pieder jūsu organizācijai."</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Šī ierīce pieder organizācijai <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>."</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Lai lietotu tālruni, velciet no ikonas"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Lai lietotu balss palīgu, velciet no ikonas"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Lai lietotu kameru, velciet no ikonas"</string>
@@ -628,6 +631,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Pieskarieties, lai izslēgtu skaņu. Var tikt izslēgti pieejamības pakalpojumu signāli."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Pieskarieties, lai iestatītu vibrozvanu."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Pieskarieties, lai izslēgtu skaņu."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"izslēgt skaņu"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ieslēgt skaņu"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrēt"</string>
@@ -1044,6 +1049,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Pievienot"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Ieteica: <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Vadīklas atjauninātas"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Ierīce ir bloķēta"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN ietver burtus vai simbolus."</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verifikācija: <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Nepareizs PIN"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index b3b4a45..59fc2d4 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"До изгрејсонце"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Се вклучува во <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"До <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Намали ја осветленоста"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC е оневозможено"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC е овозможено"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Отклучете за да користите NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Уредов е во сопственост на организацијата"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Уредов е во сопственост на <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Повлечете од иконата за телефонот"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Повлечете од иконата за гласовна помош"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Повлечете од иконата за камерата"</string>
@@ -505,7 +508,7 @@
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Безгласно"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Известувања"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Разговори"</string>
-    <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Избриши ги сите тивки известувања"</string>
+    <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Избриши ги сите бесчујни известувања"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Известувањата се паузирани од „Не вознемирувај“"</string>
     <string name="media_projection_action_text" msgid="3634906766918186440">"Започни сега"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Нема известувања"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Допрете за да исклучите звук. Можеби ќе се исклучи звукот на услугите за достапност."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Допрете за да се постави на вибрации."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Допрете за да се исклучи звукот."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"исклучен звук"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"вклучен звук"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"вибрации"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Додај"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Предложено од <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Контролите се ажурирани"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Уредот е заклучен"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-кодот содржи букви или симболи"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Потврдете го <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Погрешен PIN"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 420de5b..44883d6d 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -93,10 +93,8 @@
     <string name="screenshot_scroll_description" msgid="7855773867093272175">"സ്ക്രീൻഷോട്ട് സ്ക്രോൾ ചെയ്യുക"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"സ്ക്രീൻഷോട്ട് ഡിസ്‌മിസ് ചെയ്യുക"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"സ്‌ക്രീൻഷോട്ട് പ്രിവ്യു"</string>
-    <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
-    <skip />
-    <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
-    <skip />
+    <string name="screenshot_top_boundary" msgid="1500569103321300856">"മുകളിലുള്ള അതിർത്തി"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"ചുവടെയുള്ള അതിർത്തി"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"സ്ക്രീൻ റെക്കോർഡർ"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"സ്ക്രീൻ റെക്കോർഡിംഗ് പ്രോസസുചെയ്യുന്നു"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"ഒരു സ്ക്രീൻ റെക്കോർഡിംഗ് സെഷനായി നിലവിലുള്ള അറിയിപ്പ്"</string>
@@ -414,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"സൂര്യോദയം വരെ"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>-ന്"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> വരെ"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"തെളിച്ചം കുറയ്ക്കുക"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC പ്രവർത്തനരഹിതമാക്കി"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC പ്രവർത്തനക്ഷമമാക്കി"</string>
@@ -448,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ഉപയോഗിക്കാൻ അൺലോക്ക് ചെയ്യുക"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ഈ ഉപകരണം നിങ്ങളുടെ സ്ഥാപനത്തിന്റേതാണ്"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"ഈ ഉപകരണം <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> എന്ന സ്ഥാപനത്തിന്റേതാണ്"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ഫോൺ ഐക്കണിൽ നിന്ന് സ്വൈപ്പുചെയ്യുക"</string>
     <string name="voice_hint" msgid="7476017460191291417">"വോയ്‌സ് അസിസ്റ്റിനായുള്ള ഐക്കണിൽ നിന്ന് സ്വൈപ്പുചെയ്യുക"</string>
     <string name="camera_hint" msgid="4519495795000658637">"ക്യാമറ ഐക്കണിൽ നിന്ന് സ്വൈപ്പുചെയ്യുക"</string>
@@ -546,8 +547,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലിൽ നിങ്ങളുടെ സ്ഥാപനമൊരു സർട്ടിഫിക്കറ്റ് അതോറിറ്റി ഇൻസ്റ്റാൾ ചെയ്തിരിക്കുന്നു. നിങ്ങളുടെ സുരക്ഷിത നെറ്റ്‌വർക്ക് ട്രാഫിക്ക് നിരീക്ഷിക്കപ്പെടുകയോ പരിഷ്കരിക്കപ്പെടുയോ ചെയ്തേക്കാം."</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"നിങ്ങളുടെ ഉപകരണത്തിൽ ഒരു സർട്ടിഫിക്കറ്റ് അതോറിറ്റി ഇൻസ്റ്റാൾ ചെയ്തിരിക്കുന്നു. നിങ്ങളുടെ സുരക്ഷിത നെറ്റ്‌വർക്ക് ട്രാഫിക്ക് നിരീക്ഷിക്കപ്പെടുകയോ പരിഷ്കരിക്കപ്പെടുയോ ചെയ്തേക്കാം."</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"നിങ്ങളുടെ അഡ്‌മിൻ, നെറ്റ്‌വർക്ക് ലോഗിംഗ് ഓണാക്കിയിട്ടുണ്ട്, ഇതിന് നിങ്ങളുടെ ഉപകരണത്തിലെ ട്രാഫിക്ക് നിരീക്ഷിക്കാൻ കഴിയും."</string>
-    <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
-    <skip />
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"നിങ്ങളുടെ അഡ്‌മിൻ നെറ്റ്‌വർക്ക് ലോഗിംഗ് ഓണാക്കി, ഇത് നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലിലെ ട്രാഫിക് നിരീക്ഷിക്കുന്നു എന്നാൽ വ്യക്തിപരമായ പ്രൊഫൈലിലെ ട്രാഫിക് നിരീക്ഷിക്കുന്നില്ല."</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"നിങ്ങൾ <xliff:g id="VPN_APP">%1$s</xliff:g> എന്ന ആപ്പിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, ഇമെയിലുകൾ, ആപ്പുകൾ, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ നെറ്റ്‌വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാൻ ഈ ആപ്പിന് കഴിയും."</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"നിങ്ങൾ <xliff:g id="VPN_APP_0">%1$s</xliff:g>, <xliff:g id="VPN_APP_1">%2$s</xliff:g> എന്നീ ആപ്പുകളിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, ഇമെയിലുകൾ, ആപ്പുകൾ, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ നെറ്റ്‌വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാൻ ഈ ആപ്പിന് കഴിയും."</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"<xliff:g id="VPN_APP">%1$s</xliff:g> ആപ്പിലേക്ക് നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ കണക്റ്റുചെയ്‌തിരിക്കുന്നു, ഇമെയിലുകൾ, ആപ്‌സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ നെറ്റ്‌വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാൻ ഈ ആപ്പിന് കഴിയും."</string>
@@ -628,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. മ്യൂട്ടുചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക. ഉപയോഗസഹായി സേവനങ്ങൾ മ്യൂട്ടുചെയ്യപ്പെട്ടേക്കാം."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s വൈബ്രേറ്റിലേക്ക് സജ്ജമാക്കുന്നതിന് ടാപ്പുചെയ്യുക."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s മ്യൂട്ടുചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"മ്യൂട്ട് ചെയ്യുക"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"അൺമ്യൂട്ട് ചെയ്യുക"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"വൈബ്രേറ്റ് ചെയ്യുക"</string>
@@ -1041,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"ചേർക്കുക"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> നിർദ്ദേശിച്ചത്"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"നിയന്ത്രണങ്ങൾ അപ്ഡേറ്റ് ചെയ്തു"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"ഉപകരണം ലോക്ക് ചെയ്തു"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"പിന്നിൽ അക്ഷരങ്ങളോ ചിഹ്നങ്ങളോ അടങ്ങിയിരിക്കുന്നു"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> പരിശോധിച്ചുറപ്പിക്കുക"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"പിൻ തെറ്റാണ്"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 63547d5..efb2711 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -412,7 +412,7 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Нар мандах хүртэл"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>-д"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> хүртэл"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Гэрэлтүүлгийг багасгах"</string>
+    <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Гэрэлтүүлгийг багасгах"</string>
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC-г цуцалсан"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC-г идэвхжүүлсэн"</string>
@@ -446,6 +446,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC-г ашиглахын тулд түгжээг тайлна уу"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Энэ төхөөрөмж танай байгууллагад харьяалагддаг"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Энэ төхөөрөмж <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>-д харьяалагддаг"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Утсыг гаргахын тулд дүрс тэмдгээс шудрах"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Дуут туслахыг нээхийн тулд дүрс тэмдгээс шудрах"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Камер нээхийн тулд дүрс тэмдгийг шудрах"</string>
@@ -625,6 +627,7 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Дууг нь хаахын тулд товшино уу. Хүртээмжийн үйлчилгээний дууг хаасан."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Чичиргээнд тохируулахын тулд товшино уу."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Дууг хаахын тулд товшино уу."</string>
+    <string name="volume_ringer_change" msgid="3574969197796055532">"Хонхны горимыг өөрчлөхийн тулд товшино уу"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"дууг хаах"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"дууг нээх"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"чичрэх"</string>
@@ -1038,6 +1041,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Нэмэх"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g>-н санал болгосон"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Хяналтуудыг шинэчиллээ"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Төхөөрөмжийг түгжсэн"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ПИН нь үсэг эсвэл дүрс тэмдэгт агуулдаг"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>-г бататгах"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"ПИН код буруу байна"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index de0e7be..fcff3df 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -93,10 +93,8 @@
     <string name="screenshot_scroll_description" msgid="7855773867093272175">"स्क्रीनशॉटवर स्क्रोल करा"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"स्क्रीनशॉट डिसमिस करा"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"स्क्रीनशॉटचे पूर्वावलोकन"</string>
-    <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
-    <skip />
-    <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
-    <skip />
+    <string name="screenshot_top_boundary" msgid="1500569103321300856">"सर्वात वरची सीमा"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"तळाची सीमा"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"स्क्रीन रेकॉर्डर"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रीन रेकॉर्डिंग प्रोसेस सुरू"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"स्क्रीन रेकॉर्ड सत्रासाठी सुरू असलेली सूचना"</string>
@@ -414,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"सूर्योदयापर्यंत"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> वाजता सुरू होते"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> पर्यंत"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ब्राइटनेस कमी करा"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC अक्षम केले आहे"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC सक्षम केले आहे"</string>
@@ -448,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC वापरण्यासाठी स्क्रीन अनलॉक करा"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"हे डिव्हाइस तुमच्या संस्थेचे आहे"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"हे डिव्हाइस <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> चे आहे"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"फोनसाठी चिन्हावरून स्वाइप करा"</string>
     <string name="voice_hint" msgid="7476017460191291417">"व्हॉइस सहाय्यासाठी चिन्हावरून स्वाइप करा"</string>
     <string name="camera_hint" msgid="4519495795000658637">"कॅमेर्‍यासाठी चिन्हावरून स्वाइप करा"</string>
@@ -546,8 +547,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"आपल्या संस्थेने आपल्या कार्य प्रोफाइलवर प्रमाणपत्र अधिकार इंस्टॉल केला आहे. आपल्या सुरक्षित नेटवर्क रहदारीचे परीक्षण केले जाऊ शकते किंवा ती सुधारली जाऊ शकते."</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"या डिव्हाइसवर प्रमाणपत्र अधिकार इंस्टॉल केला आहे. आपल्या सुरक्षित नेटवर्क रहदारीचे परीक्षण केले जाऊ शकते किंवा ती सुधारली जाऊ शकते."</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"आपल्या प्रशासकाने नेटवर्क लॉगिंग सुरू केले आहे, जे आपल्या डिव्हाइसवरील रहदारीचे परीक्षण करते."</string>
-    <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
-    <skip />
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"तुमच्या ॲडमिनने नेटवर्क लॉग इन सुरू केले आहे, जे तुमच्या कार्य प्रोफाइलमधील रहदारीचे निरीक्षण करत असले तरी तुमच्या वैयक्तिक प्रोफाइलमधील रहदारीचे निरीक्षण करत नाही."</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"तुम्‍ही <xliff:g id="VPN_APP">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जे ईमेल, अ‍ॅप्स आणि वेबसाइटसहित आपल्‍या नेटवर्क क्रिया मॉनिटर करू शकते."</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"तुम्‍ही <xliff:g id="VPN_APP_0">%1$s</xliff:g> आणि <xliff:g id="VPN_APP_1">%2$s</xliff:g> शी कनेक्‍ट केले आहे, जे ईमेल, अ‍ॅप्स आणि वेबसाइटसहित आपल्‍या नेटवर्क क्रिया मॉनिटर करू शकते."</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"तुमचे कार्य प्रोफाइल <xliff:g id="VPN_APP">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जे ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या नेटवर्क क्रियाकलापाचे परीक्षण करू शकते."</string>
@@ -628,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. म्यूट करण्यासाठी टॅप करा. प्रवेशक्षमता सेवा म्यूट केल्या जाऊ शकतात."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. व्हायब्रेट सेट करण्यासाठी टॅप करा."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. म्यूट करण्यासाठी टॅप करा."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"म्यूट करा"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"म्यूट काढून टाका"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"व्हायब्रेट करा"</string>
@@ -1041,6 +1043,8 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"जोडा"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ने सुचवले आहे"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"नियंत्रणे अपडेट केली आहेत"</string>
+    <!-- no translation found for controls_tile_locked (731547768182831938) -->
+    <skip />
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"पिनमध्ये अक्षरे किंवा चिन्हे आहेत"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ची पडताळणी करा"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"चुकीचा पिन"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 319dbde..e723ec6 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Hingga matahari trbt"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Dihidupkan pada <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Hingga <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Kurangkan Kecerahan"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC dilumpuhkan"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC didayakan"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Buka kunci untuk menggunakan NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Peranti ini milik organisasi anda"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Peranti ini milik <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Leret dari ikon untuk telefon"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Leret dari ikon untuk bantuan suara"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Leret dari ikon untuk kamera"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ketik untuk meredam. Perkhidmatan kebolehaksesan mungkin diredamkan."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Ketik untuk menetapkan pada getar."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Ketik untuk meredam."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"redam"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"nyahredam"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"getar"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Tambah"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Dicadangkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kawalan dikemas kini"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Peranti dikunci"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN mengandungi huruf atau simbol"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Sahkan <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN salah"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 15ddf59..c57a94c 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"နေထွက်ချိန် အထိ"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> တွင် ဖွင့်မည်"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> အထိ"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"တောက်ပမှုကို လျှော့ရန်"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ကို ပိတ်ထားသည်"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ကို ဖွင့်ထားသည်"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ကို အသုံးပြုရန် လော့ခ်ဖွင့်ပါ"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ဤစက်ကို သင့်အဖွဲ့အစည်းက ပိုင်ဆိုင်သည်"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"ဤစက်ကို <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> က ပိုင်ဆိုင်သည်"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ဖုန်းအတွက် သင်္ကေတပုံအား ပွတ်ဆွဲပါ"</string>
     <string name="voice_hint" msgid="7476017460191291417">"အသံအကူအညီအတွက် သင်္ကေတပုံအား ပွတ်ဆွဲပါ"</string>
     <string name="camera_hint" msgid="4519495795000658637">"ကင်မရာအတွက် သင်္ကေတပုံအား ပွတ်ဆွဲပါ"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s။ အသံပိတ်ရန် တို့ပါ။ အများသုံးစွဲနိုင်မှု ဝန်ဆောင်မှုများကို အသံပိတ်ထားနိုင်ပါသည်။"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s။ တုန်ခါခြင်းသို့ သတ်မှတ်ရန်တို့ပါ။"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s။ အသံတိတ်ရန် တို့ပါ။"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"အသံတိတ်ရန်"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"အသံဖွင့်ရန်"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"တုန်ခါမှု"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"ထည့်ရန်"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> က အကြံပြုထားသည်"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"ထိန်းချုပ်မှု အပ်ဒိတ်လုပ်ပြီးပြီ"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"စက်ကိုလော့ခ်ချထားသည်"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ပင်နံပါတ်တွင် စာလုံး သို့မဟုတ် သင်္ကေတများပါဝင်သည်"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ကို အတည်ပြုခြင်း"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"ပင်နံပါတ် မှားနေသည်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 1c2fa8a..997147d 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Til soloppgang"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Slås på klokken <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Til <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduser lysstyrken"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC er slått av"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC er slått på"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås opp for å bruke NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Denne enheten tilhører organisasjonen din"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Denne enheten tilhører <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Sveip ikonet for å åpne telefon"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Sveip fra ikonet for å åpne talehjelp"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Sveip ikonet for å åpne kamera"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Trykk for å slå av lyden. Lyden kan bli slått av for tilgjengelighetstjenestene."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Trykk for å angi vibrasjon."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Trykk for å slå av lyden."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"kutt lyden"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"slå på lyden"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrer"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Legg til"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Foreslått av <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrollene er oppdatert"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Enheten er låst"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-koden inneholder bokstaver eller symboler"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Bekreft <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Feil PIN-kode"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 3ab0136f..e03ee5b 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -93,10 +93,8 @@
     <string name="screenshot_scroll_description" msgid="7855773867093272175">"स्क्रिनसट स्क्रोल गर्नुहोस्"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"स्क्रिनसट हटाउनुहोस्"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"स्क्रिनसटको पूर्वावलोकन"</string>
-    <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
-    <skip />
-    <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
-    <skip />
+    <string name="screenshot_top_boundary" msgid="1500569103321300856">"सिरानको सीमा"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"फेदको सीमा"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"स्क्रिन रेकर्डर"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रिन रेकर्डिङको प्रक्रिया अघि बढाइँदै"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"कुनै स्क्रिन रेकर्ड गर्ने सत्रका लागि चलिरहेको सूचना"</string>
@@ -414,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"सूर्योदयसम्म"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> मा सक्रिय"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> सम्म"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"स्क्रिनको चमक घटाउनुहोस्"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC लाई असक्षम पारिएको छ"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC लाई सक्षम पारिएको छ"</string>
@@ -448,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC प्रयोग गर्न स्क्रिन अनलक गर्नुहोस्"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"यो यन्त्र तपाईंको सङ्गठनको स्वामित्वमा छ"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"यो यन्त्र <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> को स्वामित्वमा छ"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"फोनको लागि आइकनबाट स्वाइप गर्नुहोस्"</string>
     <string name="voice_hint" msgid="7476017460191291417">"आवाज सहायताका लागि आइकनबाट स्वाइप गर्नुहोस्"</string>
     <string name="camera_hint" msgid="4519495795000658637">"क्यामेराको लागि आइकनबाट स्वाइप गर्नुहोस्"</string>
@@ -546,8 +547,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"तपाईंको संगठनले तपाईंको कार्य प्रोफाइलमा एउटा प्रमाणपत्र सम्बन्धी अख्तियार सुविधा स्थापना गरेको छ। तपाईंको सुरक्षित नेटवर्क ट्राफिकको अनुगमन वा परिमार्जन हुनसक्छ।"</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"यस यन्त्रमा एउटा प्रमाणपत्र सम्बन्धी अख्तियार सुविधा स्थापना गरिएको छ। तपाईंको सुरक्षित नेटवर्कको ट्राफिकको अनुगमन वा परिमार्जन हुनसक्छ।"</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"तपाईंका प्रशासकले तपाईंको यन्त्रमा ट्राफिकको अनुगमन गर्ने नेटवर्क लग गर्ने प्रक्रियालाई सक्रिय गर्नुभएको छ।"</string>
-    <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
-    <skip />
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"तपाईंका एड्मिनले \'नेटवर्क लगिङ\' सुविधा अन गर्नुभएको छ। यो सुविधाले तपाईंको कार्य प्रोफाइलको ट्राफिक अनुगमन गर्छ तर व्यक्तिगत प्रोफाइलको ट्राफिक भने अनुगमन गर्दैन।"</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"तपाईं इमेल, एप र वेबसाइटहरू लगायत तपाईंको नेटवर्कको गतिविधिको अनुगमन गर्नसक्ने <xliff:g id="VPN_APP">%1$s</xliff:g> मा जडान हुनुहुन्छ।"</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"तपाईं इमेल, एप र वेबसाइटहरू लगायत तपाईंको नेटवर्कको गतिविधिको अनुगमन गर्नसक्ने <xliff:g id="VPN_APP_0">%1$s</xliff:g> र <xliff:g id="VPN_APP_1">%2$s</xliff:g> मा जडान हुनुहुन्छ।"</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"तपाईंको कार्य प्रोफाइल तपाईंका इमेल, एप र वेबसाइटहरू लगायत तपाईंको नेटवर्कको गतिविधिको अनुगमन गर्नसक्ने <xliff:g id="VPN_APP">%1$s</xliff:g> मा जडान छ।"</string>
@@ -628,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। म्यूट गर्नाका लागि ट्याप गर्नुहोस्। पहुँच सम्बन्धी सेवाहरू म्यूट हुन सक्छन्।"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। कम्पन मोडमा सेट गर्न ट्याप गर्नुहोस्।"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। म्यूट गर्न ट्याप गर्नुहोस्।"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"म्युट गर्नुहोस्"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"अनम्युट गर्नुहोस्"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"कम्पन गर्नुहोस्"</string>
@@ -1041,6 +1043,8 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"थप्नुहोस्"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ले सिफारिस गरेको"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"नियन्त्रण सुविधाहरू अद्यावधिक गरिए"</string>
+    <!-- no translation found for controls_tile_locked (731547768182831938) -->
+    <skip />
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN मा अक्षर वा चिन्हहरू समाविष्ट हुन्छन्"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> पुष्टि गर्नुहोस्"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN मिलेन"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index dcadbf5..8ffc3f4 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Tot zonsopgang"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aan om <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Tot <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Helderheid verlagen"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is uitgeschakeld"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is ingeschakeld"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ontgrendel het apparaat om NFC te gebruiken"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Dit apparaat is eigendom van je organisatie"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Dit apparaat is eigendom van <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Swipen voor telefoon"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Swipen vanaf icoon voor spraakassistent"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Vegen voor camera"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tik om te dempen. Het geluid van toegankelijkheidsservices kan hierdoor uitgaan."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tik om in te stellen op trillen."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tik om geluid uit te zetten."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"geluid uit"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"geluid aanzetten"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"trillen"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Toevoegen"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Voorgesteld door <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Bedieningselementen geüpdated"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Apparaat vergrendeld"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Pincode bevat letters of symbolen"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> verifiëren"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Onjuiste pincode"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 955c08a..f03c31d 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"ସକାଳ ପର୍ଯ୍ୟନ୍ତ"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>ରେ ଚାଲୁ ହେବ"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> ପର୍ଯ୍ୟନ୍ତ"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ଉଜ୍ଜ୍ୱଳତା କମାନ୍ତୁ"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ଅକ୍ଷମ କରାଯାଇଛି"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ସକ୍ଷମ କରାଯାଇଛି"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ବ୍ୟବହାର କରିବାକୁ ଅନଲକ୍ କରନ୍ତୁ"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ଏହି ଡିଭାଇସଟି ଆପଣଙ୍କ ସଂସ୍ଥାର ଅଟେ"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"ଏହି ଡିଭାଇସଟି <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>ର ଅଟେ"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ଫୋନ୍‍ ପାଇଁ ଆଇକନରୁ ସ୍ୱାଇପ୍‍ କରନ୍ତୁ"</string>
     <string name="voice_hint" msgid="7476017460191291417">"ଭଏସ୍‍ ସହାୟକ ପାଇଁ ଆଇକନରୁ ସ୍ୱାଇପ୍‍ କରନ୍ତୁ"</string>
     <string name="camera_hint" msgid="4519495795000658637">"କ୍ୟାମେରା ପାଇଁ ଆଇକନରୁ ସ୍ୱାଇପ୍‍ କରନ୍ତୁ"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। ମ୍ୟୁଟ୍‍ କରିବାକୁ ଟାପ୍‍ କରନ୍ତୁ। ଆକ୍ସେସିବିଲିଟୀ ସର୍ଭିସ୍‌ ମ୍ୟୁଟ୍‍ କରାଯାଇପାରେ।"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। ଭାଇବ୍ରେଟରେ ସେଟ୍‍ କରିବାକୁ ଟାପ୍‍ କରନ୍ତୁ।"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। ମ୍ୟୁଟ୍‍ କରିବାକୁ ଟାପ୍‍ କରନ୍ତୁ।"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ମ୍ୟୁଟ୍"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ଅନ୍‍-ମ୍ୟୁଟ୍ କରନ୍ତୁ"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ଭାଇବ୍ରେଟ୍"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"ଯୋଗ କରନ୍ତୁ"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ଦ୍ଵାରା ପ୍ରସ୍ତାବିତ"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ଅପଡେଟ୍ କରାଯାଇଛି"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"ଡିଭାଇସ୍ ଲକ୍ ହୋଇଯାଇଛି"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PINରେ ଅକ୍ଷର କିମ୍ୱା ପ୍ରତୀକଗୁଡ଼ିକ ଥାଏ"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ଯାଞ୍ଚ କରନ୍ତୁ"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"ଭୁଲ PIN"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 47f56bd..459b163 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -93,10 +93,8 @@
     <string name="screenshot_scroll_description" msgid="7855773867093272175">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਨੂੰ ਸਕ੍ਰੋਲ ਕਰੋ"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਖਾਰਜ ਕਰੋ"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਪੂਰਵ-ਝਲਕ"</string>
-    <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
-    <skip />
-    <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
-    <skip />
+    <string name="screenshot_top_boundary" msgid="1500569103321300856">"ਉੱਪਰ ਦੀ ਸੀਮਾ"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"ਹੇਠਾਂ ਦੀ ਸੀਮਾ"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਰ"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਜਾਰੀ ਹੈ"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"ਕਿਸੇ ਸਕ੍ਰੀਨ ਰਿਕਾਰਡ ਸੈਸ਼ਨ ਲਈ ਚੱਲ ਰਹੀ ਸੂਚਨਾ"</string>
@@ -414,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"ਸੂਰਜ ਚੜ੍ਹਨ ਤੱਕ"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> ਵਜੇ ਚਾਲੂ"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> ਵਜੇ ਤੱਕ"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ਚਮਕ ਘਟਾਓ"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ਨੂੰ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ਨੂੰ ਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ"</string>
@@ -448,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ਵਰਤਣ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ਇਹ ਡੀਵਾਈਸ ਤੁਹਾਡੀ ਸੰਸਥਾ ਨਾਲ ਸੰਬੰਧਿਤ ਹੈ"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"ਇਹ ਡੀਵਾਈਸ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ਨਾਲ ਸੰਬੰਧਿਤ ਹੈ"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ਫ਼ੋਨ ਲਈ ਪ੍ਰਤੀਕ ਤੋਂ ਸਵਾਈਪ ਕਰੋ"</string>
     <string name="voice_hint" msgid="7476017460191291417">"ਅਵਾਜ਼ੀ ਸਹਾਇਕ ਲਈ ਪ੍ਰਤੀਕ ਤੋਂ ਸਵਾਈਪ ਕਰੋ"</string>
     <string name="camera_hint" msgid="4519495795000658637">"ਕੈਮਰੇ ਲਈ ਪ੍ਰਤੀਕ ਤੋਂ ਸਵਾਈਪ ਕਰੋ"</string>
@@ -546,8 +547,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਤੁਹਾਡੇ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਵਿੱਚ ਇੱਕ ਪ੍ਰਮਾਣ-ਪੱਤਰ ਅਥਾਰਟੀ ਸਥਾਪਤ ਕੀਤੀ ਗਈ ਹੈ। ਤੁਹਾਡੇ ਸੁਰੱਖਿਅਤ ਨੈੱਟਵਰਕ ਟਰੈਫਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ ਜਾਂ ਉਸਨੂੰ ਸੋਧਿਆ ਜਾ ਸਕਦਾ ਹੈ।"</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"ਇੱਕ ਪ੍ਰਮਾਣ-ਪੱਤਰ ਅਥਾਰਟੀ ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਸਥਾਪਤ ਕੀਤੀ ਜਾਂਦੀ ਹੈ। ਤੁਹਾਡੇ ਸੁਰੱਖਿਅਤ ਨੈੱਟਵਰਕ ਟਰੈਫਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ ਜਾਂ ਉਸਨੂੰ ਸੋਧਿਆ ਜਾ ਸਕਦਾ ਹੈ।"</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਨੇ ਨੈੱਟਵਰਕ ਲੌਗਿੰਗ ਨੂੰ ਚਾਲੂ ਕੀਤਾ ਹੋਇਆ ਹੈ, ਜੋ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਟਰੈਫਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕਰਦਾ ਹੈ।"</string>
-    <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
-    <skip />
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਨੇ ਨੈੱਟਵਰਕ ਲੌਗ-ਇਨ ਨੂੰ ਚਾਲੂ ਕੀਤਾ ਹੋਇਆ ਹੈ, ਜੋ ਤੁਹਾਡੇ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਵਿੱਚ ਟਰੈਫ਼ਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕਰਦਾ ਹੈ ਪਰ ਤੁਹਾਡੀ ਨਿੱਜੀ ਪ੍ਰੋਫਾਈਲ ਵਿੱਚ ਨਹੀਂ।"</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"ਤੁਸੀਂ <xliff:g id="VPN_APP">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲਾਂ, ਐਪਾਂ, ਅਤੇ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ।"</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"ਤੁਸੀਂ <xliff:g id="VPN_APP_0">%1$s</xliff:g> ਅਤੇ <xliff:g id="VPN_APP_1">%2$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲਾਂ, ਐਪਾਂ, ਅਤੇ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀਆਂ ਹਨ।"</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"ਤੁਹਾਡੀ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ <xliff:g id="VPN_APP">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੈ, ਜੋ ਈਮੇਲਾਂ, ਐਪਾਂ ਅਤੇ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ।"</string>
@@ -628,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। ਮਿਊਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ। ਪਹੁੰਚਯੋਗਤਾ ਸੇਵਾਵਾਂ ਮਿਊਟ ਹੋ ਸਕਦੀਆਂ ਹਨ।"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। ਥਰਥਰਾਹਟ \'ਤੇ ਸੈੱਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। ਮਿਊਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ਮਿਊਟ ਕਰੋ"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ਅਣਮਿਊਟ ਕਰੋ"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ਥਰਥਰਾਹਟ"</string>
@@ -1041,6 +1043,8 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ਵੱਲੋਂ ਸੁਝਾਇਆ ਗਿਆ"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"ਕੰਟਰੋਲ ਅੱਪਡੇਟ ਕੀਤੇ ਗਏ"</string>
+    <!-- no translation found for controls_tile_locked (731547768182831938) -->
+    <skip />
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ਪਿੰਨ ਵਿੱਚ ਅੱਖਰ ਜਾਂ ਚਿੰਨ੍ਹ ਸ਼ਾਮਲ ਹਨ"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"ਗਲਤ ਪਿੰਨ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 59c9f52..e16b5ec 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -93,10 +93,8 @@
     <string name="screenshot_scroll_description" msgid="7855773867093272175">"Przewiń zrzut ekranu"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Zamknij zrzut ekranu"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Podgląd zrzutu ekranu"</string>
-    <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
-    <skip />
-    <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
-    <skip />
+    <string name="screenshot_top_boundary" msgid="1500569103321300856">"Górna granica"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Dolna granica"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Nagrywanie ekranu"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Przetwarzam nagrywanie ekranu"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Stałe powiadomienie o sesji rejestrowania zawartości ekranu"</string>
@@ -418,7 +416,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do wschodu słońca"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Włącz o <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Zmniejsz jasność"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"Komunikacja NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"Komunikacja NFC jest wyłączona"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"Komunikacja NFC jest włączona"</string>
@@ -452,6 +451,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Odblokuj, by użyć komunikacji NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"To urządzenie należy do Twojej organizacji"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Właściciel tego urządzenia: <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Aby włączyć telefon, przesuń palcem od ikony"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Aby uzyskać pomoc głosową, przesuń palcem od ikony"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Przesuń palcem od ikony, by włączyć aparat"</string>
@@ -552,8 +553,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Twoja organizacja zainstalowała urząd certyfikacji w Twoim profilu służbowym. Zabezpieczony ruch w sieci może być monitorowany i zmieniany."</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"Urząd certyfikacji zainstalowany na tym urządzeniu. Twój zabezpieczony ruch w sieci może być monitorowany i zmieniany."</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"Administrator włączył rejestrowanie sieciowe, które pozwala monitorować ruch na Twoim urządzeniu."</string>
-    <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
-    <skip />
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"Administrator włączył rejestrowanie sieciowe, które pozwala monitorować ruch na Twoim profilu służbowym, ale nie na profilu osobistym."</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"Łączysz się z aplikacją <xliff:g id="VPN_APP">%1$s</xliff:g>, która może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"Łączysz się z aplikacjami <xliff:g id="VPN_APP_0">%1$s</xliff:g> i <xliff:g id="VPN_APP_1">%2$s</xliff:g>, które mogą monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"Twój profil służbowy jest połączony z aplikacją <xliff:g id="VPN_APP">%1$s</xliff:g>, która może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
@@ -634,6 +634,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Kliknij, by wyciszyć. Ułatwienia dostępu mogą być wyciszone."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Kliknij, by włączyć wibracje."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Kliknij, by wyciszyć."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"wycisz"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"wyłącz wyciszenie"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"włącz wibracje"</string>
@@ -1053,6 +1055,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugestia: <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Zaktualizowano elementy sterujące"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Urządzenie zablokowane"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Kod PIN zawiera litery lub symbole"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Sprawdź urządzenie <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Nieprawidłowy kod PIN"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index fca802d..efe0f06 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Até o nascer do sol"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ativar: <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Até: <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduzir brilho"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"A NFC está desativada"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"A NFC está ativada"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloqueie para usar a NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence à sua organização"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertence à organização <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Deslize a partir do ícone do telefone"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Deslize a partir do ícone de assistência de voz"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Deslize a partir do ícone da câmera"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toque para silenciar. É possível que os serviços de acessibilidade sejam silenciados."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toque para configurar para vibrar."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toque para silenciar."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"desativar o som"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ativar o som"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
@@ -791,7 +796,7 @@
     <string name="keyboard_key_media_stop" msgid="1509943745250377699">"Parar"</string>
     <string name="keyboard_key_media_next" msgid="8502476691227914952">"Avançar"</string>
     <string name="keyboard_key_media_previous" msgid="5637875709190955351">"Anterior"</string>
-    <string name="keyboard_key_media_rewind" msgid="3450387734224327577">"Retroceder"</string>
+    <string name="keyboard_key_media_rewind" msgid="3450387734224327577">"Voltar"</string>
     <string name="keyboard_key_media_fast_forward" msgid="3572444327046911822">"Avançar rapidamente"</string>
     <string name="keyboard_key_page_up" msgid="173914303254199845">"Page Up"</string>
     <string name="keyboard_key_page_down" msgid="9035902490071829731">"Page Down"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Adicionar"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controles atualizados"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Dispositivo bloq."</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"O PIN contém letras ou símbolos"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verificar <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN incorreto"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 9b4d45b..3a82feb 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Até ao amanhecer"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ativado à(s) <xliff:g id="TIME">%s</xliff:g>."</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Até à(s) <xliff:g id="TIME">%s</xliff:g>."</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduzir o brilho"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"O NFC está desativado"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"O NFC está ativado"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquear para utilizar o NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence à sua entidade."</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertence à entidade <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>."</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Deslize rapid. a partir do ícone para aceder ao telemóvel"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Deslize rapid. a partir do ícone para aceder ao assist. voz"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Deslize rapidamente a partir do ícone para aceder à câmara"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toque para desativar o som. Os serviços de acessibilidade podem ser silenciados."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toque para ativar a vibração."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toque para desativar o som."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"desativar som"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"reativar som"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Adicionar"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controlos atualizados"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Dispositivo bloq."</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"O PIN contém letras ou símbolos."</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Validar <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN incorreto"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index fca802d..efe0f06 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Até o nascer do sol"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ativar: <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Até: <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduzir brilho"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"A NFC está desativada"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"A NFC está ativada"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloqueie para usar a NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence à sua organização"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertence à organização <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Deslize a partir do ícone do telefone"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Deslize a partir do ícone de assistência de voz"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Deslize a partir do ícone da câmera"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toque para silenciar. É possível que os serviços de acessibilidade sejam silenciados."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toque para configurar para vibrar."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toque para silenciar."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"desativar o som"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ativar o som"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
@@ -791,7 +796,7 @@
     <string name="keyboard_key_media_stop" msgid="1509943745250377699">"Parar"</string>
     <string name="keyboard_key_media_next" msgid="8502476691227914952">"Avançar"</string>
     <string name="keyboard_key_media_previous" msgid="5637875709190955351">"Anterior"</string>
-    <string name="keyboard_key_media_rewind" msgid="3450387734224327577">"Retroceder"</string>
+    <string name="keyboard_key_media_rewind" msgid="3450387734224327577">"Voltar"</string>
     <string name="keyboard_key_media_fast_forward" msgid="3572444327046911822">"Avançar rapidamente"</string>
     <string name="keyboard_key_page_up" msgid="173914303254199845">"Page Up"</string>
     <string name="keyboard_key_page_down" msgid="9035902490071829731">"Page Down"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Adicionar"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controles atualizados"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Dispositivo bloq."</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"O PIN contém letras ou símbolos"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verificar <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN incorreto"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 3a06921..18093b4 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -414,7 +414,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Până la răsărit"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Activată la <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Până la <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Reduceți luminozitatea"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"Serviciul NFC este dezactivat"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"Serviciul NFC este activat"</string>
@@ -448,6 +449,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Deblocați pentru a folosi NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Dispozitivul aparține organizației dvs."</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Acest dispozitiv aparține organizației <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Glisați dinspre telefon"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Glisați dinspre pictogramă pentru asistentul vocal"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Glisați pentru a fotografia"</string>
@@ -628,6 +631,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Atingeți pentru a dezactiva sunetul. Sunetul se poate dezactiva pentru serviciile de accesibilitate."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Atingeți pentru a seta pe vibrații."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Atingeți pentru a dezactiva sunetul."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"dezactivați sunetul"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"activați sunetul"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrații"</string>
@@ -1044,6 +1049,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Adăugați"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugerat de <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"S-au actualizat comenzile"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Dispozitiv blocat"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Codul PIN conține litere sau simboluri"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verificați <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Cod PIN greșit"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index a81401a..a9f7c02 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -416,7 +416,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"До рассвета"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Включить в <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"До <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Уменьшение яркости"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"Модуль NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"Модуль NFC отключен"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"Модуль NFC включен"</string>
@@ -450,6 +451,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Чтобы использовать NFC, разблокируйте устройство."</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Это устройство принадлежит вашей организации"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Этим устройством владеет организация \"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>\""</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Телефон: проведите от значка"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Аудиоподсказки: проведите от значка"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Камера: проведите от значка"</string>
@@ -631,6 +634,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Нажмите, чтобы выключить звук. Специальные возможности могут прекратить работу."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Нажмите, чтобы включить вибрацию."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Нажмите, чтобы выключить звук."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"отключить звук"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"включить звук"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"включить вибрацию"</string>
@@ -1050,6 +1055,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Добавить"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Предложено приложением \"<xliff:g id="APP">%s</xliff:g>\""</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Элементы управления обновлены."</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Устройство заблокировано"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-код содержит буквы или символы"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Подтвердите устройство \"<xliff:g id="DEVICE">%s</xliff:g>\""</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Неверный PIN-код"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index f62eae0..5134e04 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -412,7 +412,7 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"හිරු නගින තෙක්"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>ට ක්‍රියාත්මකයි"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> තෙක්"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"දීප්තිය අඩු කරන්න"</string>
+    <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"දීප්තිය අඩු කරන්න"</string>
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC අබලයි"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC සබලයි"</string>
@@ -446,6 +446,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC භාවිත කිරීමට අගුලු හරින්න"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"මෙම උපාංගය ඔබේ සංවිධානයට අයිතිය"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"මෙම උපාංගය <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> සංවිධානයට අයිතිය"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"දුරකථනය සඳහා නිරූපකය වෙතින් ස්වයිප් කරන්න"</string>
     <string name="voice_hint" msgid="7476017460191291417">"හඬ සහාය සඳහා නිරූපකය වෙතින් ස්වයිප් කරන්න"</string>
     <string name="camera_hint" msgid="4519495795000658637">"කැමරාව සඳහා නිරූපකය වෙතින් ස්වයිප් කරන්න"</string>
@@ -625,6 +627,7 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. නිහඬ කිරීමට තට්ටු කරන්න. ප්‍රවේශ්‍යතා සේවා නිහඬ කළ හැකිය."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. කම්පනය කිරීමට සකස් කිරීමට තට්ටු කරන්න."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. නිහඬ කිරීමට තට්ටු කරන්න."</string>
+    <string name="volume_ringer_change" msgid="3574969197796055532">"නාදකය වෙනස් කිරීමට තට්ටු කරන්න"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"නිහඬ කරන්න"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"නිශ්ශබ්දතාවය ඉවත් කරන්න"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"කම්පනය"</string>
@@ -1038,6 +1041,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"එක් කරන්න"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"යෝජනා කළේ <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"පාලන යාවත්කාලීනයි"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"උපාංගය අගුලු දමා ඇත"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN හි අකුරු හෝ සංකේත අඩංගු වේ"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> සත්‍යාපනය කරන්න"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"වැරදි PIN එකකි"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 927b2ac..d514b66 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -416,7 +416,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do východu slnka"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Zapne sa o <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Znížiť jas"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je deaktivované"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je aktivované"</string>
@@ -450,6 +451,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ak chcete použiť NFC, odomknite"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Toto zariadenie patrí vašej organizácii"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Toto zariadení patrí organizácii <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Telefón otvoríte prejdením prstom od ikony"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Hlasového asistenta otvoríte prejdením prstom od ikony"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Fotoaparát otvoríte prejdením prstom od ikony"</string>
@@ -631,6 +634,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Klepnutím vypnite zvuk. Služby dostupnosti je možné stlmiť."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Klepnutím nastavíte vibrovanie."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Klepnutím vypnete zvuk."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"vypnite zvuk"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"zapnite zvuk"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"zapnite vibrovanie"</string>
@@ -1050,6 +1055,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Pridať"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Navrhuje <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Ovládanie bolo aktualizované"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Uzamknuté zariadenie"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN obsahuje písmená či symboly"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>, overenie"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Nesprávny PIN"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 881ba91..b7b2dd0 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -416,7 +416,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do sončnega vzhoda"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Vklop ob <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Zmanjšanje svetlosti"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"Tehnologija NFC je onemogočena"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"Tehnologija NFC je omogočena"</string>
@@ -450,6 +451,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Odklenite napravo, če želite uporabljati NFC."</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Ta naprava pripada vaši organizaciji"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Ta naprava pripada organizaciji <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Povlecite z ikone za telefon"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Povlecite z ikone za glasovnega pomočnika"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Povlecite z ikone za fotoaparat"</string>
@@ -631,6 +634,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dotaknite se, če želite izklopiti zvok. V storitvah za ljudi s posebnimi potrebami bo morda izklopljen zvok."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Dotaknite se, če želite nastaviti vibriranje."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Dotaknite se, če želite izklopiti zvok."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"izklop zvoka"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"vklop zvoka"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibriranje"</string>
@@ -1050,6 +1055,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Dodaj"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Predlagala aplikacija <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrolniki so posodobljeni"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Naprava je zaklenjena"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Koda PIN vsebuje črke ali simbole"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Preverjanje naprave <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Napačna koda PIN"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 29d1661..9f4c1e1 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Deri në lindje të diellit"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aktiv në <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Deri në <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Redukto ndriçimin"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC është çaktivizuar"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC është aktivizuar"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Shkyçe për të përdorur NFC-në"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Kjo pajisje i përket organizatës sate"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Kjo pajisje i përket <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Rrëshqit për të hapur telefonin"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Rrëshqit për të hapur ndihmën zanore"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Rrëshqit për të hapur kamerën"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Trokit për të çaktivizuar. Shërbimet e qasshmërisë mund të çaktivizohen."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Trokit për ta vendosur në dridhje."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Trokit për ta çaktivizuar."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"çaktivizo audion"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"aktivizo audion"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"lësho dridhje"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Shto"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugjeruar nga <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrollet u përditësuan"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Pajisja është e kyçur"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Kodi PIN përmban shkronja ose simbole"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verifiko <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Kod PIN i gabuar"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index c021bfa..5c2fbac 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -414,7 +414,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"До изласка сунца"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Укључује се у <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"До <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Смањи осветљеност"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC је онемогућен"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC је омогућен"</string>
@@ -448,6 +449,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Откључајте да бисте користили NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Овај уређај припада организацији"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Овај уређај припада организацији <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Превуците од иконе за телефон"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Превуците од иконе за гласовну помоћ"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Превуците од иконе за камеру"</string>
@@ -628,6 +631,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Додирните да бисте искључили звук. Звук услуга приступачности ће можда бити искључен."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Додирните да бисте подесили на вибрацију."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Додирните да бисте искључили звук."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"искључите звук"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"укључите звук"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"вибрација"</string>
@@ -1044,6 +1049,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Додај"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Предлаже <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Контроле су ажуриране"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Уређај је закључан"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN садржи слова или симболе"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Верификујте: <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Погрешан PIN"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index e38d7cd..5ca41ed 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Till soluppgången"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aktivera kl. <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Till <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Minska ljusstyrkan"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC är inaktiverat"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC är aktiverat"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås upp om du vill använda NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Den här enheten tillhör organisationen"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Den här enheten tillhör <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Svep från ikonen och öppna telefonen"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Svep från ikonen och öppna röstassistenten"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Svep från ikonen och öppna kameran"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tryck här om du vill stänga av ljudet. Tillgänglighetstjänsterna kanske inaktiveras."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tryck här om du vill aktivera vibrationsläget."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tryck här om du vill stänga av ljudet."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"stänga av ljudet"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"slå på ljudet"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibration"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Lägg till"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Förslag från <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Snabbkontroller uppdaterade"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Enheten är låst"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Pinkoden innehåller bokstäver eller symboler"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Verifiera <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Fel pinkod"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index a775d14..768e10c 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Hadi macheo"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Itawashwa saa <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Hadi saa <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Punguza Ung\'aavu"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC imezimwa"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC imewashwa"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Fungua ili utumie NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Kifaa hiki kinamilikiwa na shirika lako"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Kifaa hiki kinamilikiwa na <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Telezesha kidole kutoka kwa aikoni ili ufikie simu"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Telezesha kidole kutoka aikoni ili upate mapendekezo ya sauti"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Telezesha kidole kutoka aikoni ili ufikie kamera"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Gusa ili ukomeshe. Huenda ikakomesha huduma za zana za walio na matatizo ya kuona au kusikia."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Gusa ili uweke mtetemo."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Gusa ili usitishe."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"zima sauti"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"washa sauti"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"tetema"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Weka"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Kimependekezwa na <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Umesasisha vidhibiti"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Kifaa kimefungwa"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN ina herufi au alama"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Thibitisha <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Nambari ya PIN si sahihi"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 335a529..2ea5a6a 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"காலை வரை"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>க்கு ஆன் செய்"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> வரை"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ஒளிர்வைக் குறை"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC முடக்கப்பட்டது"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC இயக்கப்பட்டது"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCயைப் பயன்படுத்த அன்லாக் செய்யவும்"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"இந்த சாதனம் உங்கள் நிறுவனத்துக்கு சொந்தமானது"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"இந்த சாதனம் <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> நிறுவனத்துக்கு சொந்தமானது"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ஃபோனிற்கு ஐகானிலிருந்து ஸ்வைப் செய்யவும்"</string>
     <string name="voice_hint" msgid="7476017460191291417">"குரல் உதவிக்கு ஐகானிலிருந்து ஸ்வைப் செய்யவும்"</string>
     <string name="camera_hint" msgid="4519495795000658637">"கேமராவிற்கு ஐகானிலிருந்து ஸ்வைப் செய்யவும்"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ஒலியடக்க, தட்டவும். அணுகல்தன்மை சேவைகள் ஒலியடக்கப்படக்கூடும்."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. அதிர்விற்கு அமைக்க, தட்டவும்."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. ஒலியடக்க, தட்டவும்."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ஒலியடக்கும்"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ஒலி இயக்கும்"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"அதிர்வுறும்"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"சேர்"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ஆப்ஸால் பரிந்துரைக்கப்பட்டது"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"கட்டுப்பாடுகள் மாற்றப்பட்டன"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"சாதனம் பூட்டப்பட்டது"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"பின்னில் எழுத்துகள் அல்லது குறிகள் உள்ளன"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ஐச் சரிபார்த்தல்"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"தவறான பின்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 8013d6e..03af2a0 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -93,10 +93,8 @@
     <string name="screenshot_scroll_description" msgid="7855773867093272175">"స్క్రీన్‌షాట్‌కు స్క్రోల్ చేయండి"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"స్క్రీన్‌షాట్‌ను విస్మరించు"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"స్క్రీన్‌షాట్ ప్రివ్యూ"</string>
-    <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
-    <skip />
-    <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
-    <skip />
+    <string name="screenshot_top_boundary" msgid="1500569103321300856">"ఎగువ సరిహద్దు"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"దిగువ సరిహద్దు"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"స్క్రీన్ రికార్డర్"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"స్క్రీన్ రికార్డింగ్ అవుతోంది"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"స్క్రీన్ రికార్డ్ సెషన్ కోసం ఆన్‌గోయింగ్ నోటిఫికేషన్"</string>
@@ -414,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"సూర్యోదయం వరకు"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> కు ఆన్ అవుతుంది"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> వరకు"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ప్రకాశాన్ని తగ్గించండి"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC నిలిపివేయబడింది"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ప్రారంభించబడింది"</string>
@@ -448,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCని ఉపయోగించడానికి అన్‌లాక్ చేయండి"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ఈ పరికరం మీ సంస్థకు చెందినది"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"ఈ పరికరం <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>కు చెందినది"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"ఫోన్ కోసం చిహ్నాన్ని స్వైప్ చేయండి"</string>
     <string name="voice_hint" msgid="7476017460191291417">"వాయిస్ అసిస్టెంట్ చిహ్నం నుండి స్వైప్"</string>
     <string name="camera_hint" msgid="4519495795000658637">"కెమెరా కోసం చిహ్నాన్ని స్వైప్ చేయండి"</string>
@@ -546,8 +547,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"మీ కార్యాలయ ప్రొఫైల్‌లో మీ సంస్థ ఒక ప్రమాణపత్ర అధికారాన్ని ఇన్‌స్టాల్ చేసింది. మీ సురక్షిత నెట్‌వర్క్ ట్రాఫిక్ పర్యవేక్షించబడవచ్చు లేదా సవరించబడవచ్చు."</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"ఈ పరికరంలో ప్రమాణపత్ర అధికారం ఇన్‌స్టాల్ చేయబడింది. మీ సురక్షిత నెట్‌వర్క్ ట్రాఫిక్ పర్యవేక్షించబడవచ్చు లేదా సవరించబడవచ్చు."</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"మీ నిర్వాహకులు మీ పరికరంలోని ట్రాఫిక్‌ని పర్యవేక్షించగల నెట్‌వర్క్ లాగింగ్‌ని ఆన్ చేసారు."</string>
-    <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
-    <skip />
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"మీ అడ్మిన్ నెట్‌వర్క్ లాగింగ్‌ను ఆన్ చేశారు, ఇది మీ వర్క్ ప్రొఫైల్‌లోని ట్రాఫిక్‌ను పర్యవేక్షిస్తుంది కానీ మీ వ్యక్తిగత ప్రొఫైల్‌లో కాదు."</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"మీరు <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, యాప్‌లు మరియు వెబ్‌సైట్‌లతో సహా మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"మీరు ఇమెయిల్‌లు, యాప్‌లు మరియు వెబ్‌సైట్‌లతో సహా మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="VPN_APP_0">%1$s</xliff:g> మరియు <xliff:g id="VPN_APP_1">%2$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు."</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"మీ కార్యాలయ ప్రొఫైల్ ఇమెయిల్‌లు, యాప్‌లు మరియు వెబ్‌సైట్‌లతో సహా మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడింది."</string>
@@ -628,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. మ్యూట్ చేయడానికి నొక్కండి. యాక్సెస్ సామర్థ్య సేవలు మ్యూట్ చేయబడవచ్చు."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. వైబ్రేట్ అయ్యేలా సెట్ చేయడం కోసం నొక్కండి."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. మ్యూట్ చేయడానికి నొక్కండి."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"మ్యూట్ చేయి"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"అన్‌మ్యూట్ చేయి"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"వైబ్రేట్"</string>
@@ -1041,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"జోడించండి"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ద్వారా సూచించబడింది"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"నియంత్రణలు అప్‌డేట్ అయ్యాయి"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"పరికరంలాక్ చేయబడింది"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"పిన్ అక్షరాలను లేదా చిహ్నాలను కలిగి ఉంది"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>ను వెరిఫై చేయండి"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"పిన్ తప్పు"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index c55b7f0..5e37ed8 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"จนพระอาทิตย์ขึ้น"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"เปิดเวลา <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"จนถึง <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"ลดความสว่าง"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ถูกปิดใช้งาน"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"เปิดใช้งาน NFC แล้ว"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"ปลดล็อกเพื่อใช้ NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"องค์กรของคุณเป็นเจ้าของอุปกรณ์นี้"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> เป็นเจ้าของอุปกรณ์นี้"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"เลื่อนไอคอนโทรศัพท์"</string>
     <string name="voice_hint" msgid="7476017460191291417">"เลื่อนไอคอนตัวช่วยเสียง"</string>
     <string name="camera_hint" msgid="4519495795000658637">"เลื่อนไอคอนกล้อง"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s แตะเพื่อปิดเสียง อาจมีการปิดเสียงบริการการเข้าถึง"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s แตะเพื่อตั้งค่าให้สั่น"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s แตะเพื่อปิดเสียง"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ปิดเสียง"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"เปิดเสียง"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"สั่น"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"เพิ่ม"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"แนะนำโดย <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"อัปเดตตัวควบคุมแล้ว"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"อุปกรณ์ถูกล็อก"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN ประกอบด้วยตัวอักษรหรือสัญลักษณ์"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"ยืนยัน <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN ไม่ถูกต้อง"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 33bd659..18313e4 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Hanggang sunrise"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ma-o-on nang <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Hanggang <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Bawasan ang Liwanag"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"Naka-disable ang NFC"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"Naka-enable ang NFC"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"I-unlock para magamit ang NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Pagmamay-ari ng iyong organisasyon ang device na ito"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Pagmamay-ari ng <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ang device na ito"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Mag-swipe mula sa icon para sa telepono"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Mag-swipe mula sa icon para sa voice assist"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Mag-swipe mula sa icon para sa camera"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. I-tap upang i-mute. Maaaring i-mute ang mga serbisyo sa Accessibility."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. I-tap upang itakda na mag-vibrate."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. I-tap upang i-mute."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"i-mute"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"i-unmute"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"i-vibrate"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Idagdag"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Iminungkahi ng <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Na-update na ang mga kontrol"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Naka-lock ang device"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"May mga titik o simbolo ang PIN"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"I-verify ang <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Maling PIN"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 4bacfb9..6b3015c 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Sabaha kadar"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Açılacağı saat: <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Şu saate kadar: <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Parlaklığı Azalt"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC devre dışı"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC etkin"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC\'yi kullanmak için kilidi açın"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Bu cihaz, kuruluşunuza ait"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Bu cihaz <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> adlı kuruluşa ait"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Telefon için, simgeden hızlıca kaydırın"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Sesli yardım için, simgeden hızlıca kaydırın"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Kamera için, simgeden hızlıca kaydırın"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Sesi kapatmak için dokunun. Erişilebilirlik hizmetlerinin sesi kapatılabilir."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Titreşime ayarlamak için dokunun."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Sesi kapatmak için dokunun."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"sesi  kapat"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"sesi aç"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"titreşim"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Ekle"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> tarafından önerildi"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Denetimler güncellendi"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Cihaz kilitlendi"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN, harf veya simge içerir"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> cihazını doğrulayın"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Yanlış PIN"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 4a0746c..12b4830 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -416,7 +416,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"До сходу сонця"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Вмикається о <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"До <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Зменшувати яскравість"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC вимкнено"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ввімкнено"</string>
@@ -450,6 +451,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Розблокуйте екран, щоб скористатись NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Цей пристрій належить вашій організації"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Цей пристрій належить організації \"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>\""</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Телефон: проведіть пальцем від значка"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Голосові підказки: проведіть пальцем від значка"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Камера: проведіть пальцем від значка"</string>
@@ -631,6 +634,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Торкніться, щоб вимкнути звук. Спеціальні можливості може бути вимкнено."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Торкніться, щоб налаштувати вібросигнал."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Торкніться, щоб вимкнути звук."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"вимкнути звук"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"увімкнути звук"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"увімкнути вібросигнал"</string>
@@ -1050,6 +1055,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Додати"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Запропоновано додатком <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Елементи керування оновлено"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Пристрій заблоковано"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-код містить літери чи символи"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Неправильний PIN-код"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index f2e0273..3668f7e 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"طلوع آفتاب تک"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"آن ہوگی بوقت <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> تک"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"چمک کم کریں"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"‏NFC غیر فعال ہے"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"‏NFC فعال ہے"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"‏NFC استعمال کرنے کیلئے غیر مقفل کریں"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"یہ آلہ آپ کی تنظیم کا ہے"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"یہ آلہ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> کا ہے"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"فون کیلئے آئیکن سے سوائپ کریں"</string>
     <string name="voice_hint" msgid="7476017460191291417">"صوتی معاون کیلئے آئیکن سے سوائپ کریں"</string>
     <string name="camera_hint" msgid="4519495795000658637">"کیمرہ کیلئے آئیکن سے سوائپ کریں"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"‏‎%1$s۔ خاموش کرنے کیلئے تھپتھپائیں۔ ایکسیسبیلٹی سروسز شاید خاموش ہوں۔"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"‏‎%1$s۔ ارتعاش پر سیٹ کرنے کیلئے تھپتھپائیں۔"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"‏‎%1$s۔ خاموش کرنے کیلئے تھپتھپائیں۔"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"خاموش کریں"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"غیر خاموش کریں"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"وائبریٹ"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"شامل کریں"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> کی طرف سے تجویز کردہ"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"کنٹرولز اپ ڈیٹ کیے گئے"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"آلہ مقفل کر دیا گیا"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"‏PIN میں حروف یا علامات شامل ہیں"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"‫<xliff:g id="DEVICE">%s</xliff:g> کی تصدیق کریں"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"‏غلط PIN"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index fab65b1..0732c7f 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -93,10 +93,8 @@
     <string name="screenshot_scroll_description" msgid="7855773867093272175">"Skrinshotni aylantirish"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Skrinshotni yopish"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Skrinshotga razm solish"</string>
-    <!-- no translation found for screenshot_top_boundary (1500569103321300856) -->
-    <skip />
-    <!-- no translation found for screenshot_bottom_boundary (5657242629526407311) -->
-    <skip />
+    <string name="screenshot_top_boundary" msgid="1500569103321300856">"Yuqori chegara"</string>
+    <string name="screenshot_bottom_boundary" msgid="5657242629526407311">"Quyi chegara"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Ekrandan yozib olish"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekran yozib olinmoqda"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekrandan yozib olish seansi uchun joriy bildirishnoma"</string>
@@ -414,7 +412,7 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Quyosh chiqqunicha"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> da yoqiladi"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> gacha"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Yorqinlikni pasaytirish"</string>
+    <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Yorqinlikni pasaytirish"</string>
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC o‘chiq"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC yoniq"</string>
@@ -448,6 +446,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ishlatish uchun qurilma qulfini oching"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Bu qurilma tashkilotingizga tegishli"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Bu qurilma <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> tashkilotiga tegishli"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Telefonni ochish uchun suring"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Ovozli yordam: belgidan boshlab suring"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Kamerani ochish uchun suring"</string>
@@ -546,8 +546,7 @@
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Tashkilotingiz ishchi profilingizga CA sertifikatini o‘rnatdi. U himoyalangan tarmoq trafigini nazorat qilishi va o‘zgartirishi mumkin."</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"Qurilmada CA sertifikati o‘rnatilgan. U himoyalangan tarmoq trafigini nazorat qilishi va o‘zgartirishi mumkin."</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"Administrator qurilmangizdagi trafikni nazorat qiluvchi tarmoq jurnalini yoqdi."</string>
-    <!-- no translation found for monitoring_description_managed_profile_network_logging (6932303843097006037) -->
-    <skip />
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"Administrator ish profilingizdagi trafikni nazorat qiluvchi tarmoq jurnalini yoqdi (shaxsiy profildan maʼlumotlar olinmaydi)."</string>
     <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"<xliff:g id="VPN_APP">%1$s</xliff:g> ilovasi ishga tushirilgan. U internetdagi harakatlaringiz, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
     <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> va <xliff:g id="VPN_APP_1">%2$s</xliff:g> ilovalari ishga tushirilgan. Ular tarmoqdagi, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
     <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"Ishchi profilingizda tarmoqdagi, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin bo‘lgan <xliff:g id="VPN_APP">%1$s</xliff:g> ilovasi ishga tushirilgan."</string>
@@ -628,6 +627,7 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ovozini o‘chirish uchun ustiga bosing. Maxsus imkoniyatlar ishlamasligi mumkin."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tebranishni yoqish uchun ustiga bosing."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Ovozsiz qilish uchun ustiga bosing."</string>
+    <string name="volume_ringer_change" msgid="3574969197796055532">"Jiringlagich rejimini oʻzgartirish uchun bosing"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ovozsiz qilish"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ovozni yoqish"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"tebranish"</string>
@@ -1041,6 +1041,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Kiritish"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> taklif etgan"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Boshqaruv elementlari yangilandi"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Qurilma qulflandi"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Harflar yoki maxsus belgilardan iborat PIN kod"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Tekshirish: <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN kod xato"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 366f755..cc89303 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Cho đến khi trời sáng"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Bật vào lúc <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Cho đến <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Giảm độ sáng"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC đã được tắt"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC đã được bật"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Mở khóa để sử dụng NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Thiết bị này thuộc về tổ chức của bạn"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Thiết bị này thuộc về <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Vuốt từ biểu tượng để mở điện thoại"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Vuốt từ biểu tượng để mở trợ lý thoại"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Vuốt từ biểu tượng để mở máy ảnh"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Nhấn để tắt tiếng. Bạn có thể tắt tiếng dịch vụ trợ năng."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Nhấn để đặt chế độ rung."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Nhấn để tắt tiếng."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"tắt tiếng"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"bật tiếng"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"rung"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Thêm"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Do <xliff:g id="APP">%s</xliff:g> đề xuất"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Đã cập nhật các tùy chọn điều khiển"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Đã khóa thiết bị"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Mã PIN chứa các ký tự hoặc ký hiệu"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Xác minh <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Mã PIN sai"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index c25ad27..92f9e67 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"在日出时关闭"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"在<xliff:g id="TIME">%s</xliff:g> 开启"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"直到<xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"调低亮度"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC 已停用"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC 已启用"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"需要解锁才能使用 NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"此设备归贵单位所有"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"此设备归<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>所有"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"滑动图标即可拨打电话"</string>
     <string name="voice_hint" msgid="7476017460191291417">"滑动图标即可打开语音助理"</string>
     <string name="camera_hint" msgid="4519495795000658637">"滑动图标即可打开相机"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s。点按即可设为静音,但可能会同时将无障碍服务设为静音。"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s。点按即可设为振动。"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s。点按即可设为静音。"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"静音"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"取消静音"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"振动"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"添加"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"来自<xliff:g id="APP">%s</xliff:g>的建议"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"控件已更新"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"设备已锁定"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN 码由字母或符号组成"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"验证<xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN 码错误"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index aa7b47a..d2a232b 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -412,7 +412,7 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"在日出時關閉"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"於<xliff:g id="TIME">%s</xliff:g>開啟"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"直至<xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"調低亮度"</string>
+    <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"調低亮度"</string>
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC 已停用"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC 已啟用"</string>
@@ -446,6 +446,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"解鎖方可使用 NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"此裝置屬於您的機構"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"此裝置屬於「<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>」"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"從圖示滑動即可使用手機功能"</string>
     <string name="voice_hint" msgid="7476017460191291417">"從圖示滑動即可使用語音助手"</string>
     <string name="camera_hint" msgid="4519495795000658637">"從圖示滑動即可使用相機功能"</string>
@@ -625,6 +627,7 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s。輕按即可設為靜音。無障礙功能服務可能已經設為靜音。"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s。輕按即可設為震動。"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s。輕按即可設為靜音。"</string>
+    <string name="volume_ringer_change" msgid="3574969197796055532">"輕按即可變更響鈴模式"</string>
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"靜音"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"取消靜音"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"震動"</string>
@@ -1038,6 +1041,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"新增"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"由「<xliff:g id="APP">%s</xliff:g>」提供的建議"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"已更新控制項"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"裝置已上鎖"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN 含有字母或符號"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"驗證<xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN 錯誤"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index ca8db2e..396484a 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -71,7 +71,7 @@
     <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"目前登入這部裝置的使用者無法開啟無線偵錯功能。如要使用這項功能,請切換到主要使用者。"</string>
     <string name="usb_contaminant_title" msgid="894052515034594113">"USB 連接埠已停用"</string>
     <string name="usb_contaminant_message" msgid="7730476585174719805">"為了避免液體或灰塵導致你的裝置受損,系統已停用 USB 連接埠,因此目前無法偵測任何配件。\n\n系統會在可繼續使用 USB 連接埠時通知你。"</string>
-    <string name="usb_port_enabled" msgid="531823867664717018">"USB 通訊埠已啟用,可偵測充電器和配件"</string>
+    <string name="usb_port_enabled" msgid="531823867664717018">"USB 連接埠已啟用,可偵測充電器和配件"</string>
     <string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"啟用 USB 連接埠"</string>
     <string name="learn_more" msgid="4690632085667273811">"瞭解詳情"</string>
     <string name="compat_mode_on" msgid="4963711187149440884">"放大為全螢幕"</string>
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"於日出時關閉"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"開啟時間:<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"關閉時間:<xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"調低亮度"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC 已停用"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC 已啟用"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"如要使用 NFC,請先解鎖"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"這部裝置的擁有者為貴機構"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"這部裝置的擁有者為「<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>」"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"滑動手機圖示即可啟用"</string>
     <string name="voice_hint" msgid="7476017460191291417">"滑動語音小幫手圖示即可啟用"</string>
     <string name="camera_hint" msgid="4519495795000658637">"滑動相機圖示即可啟用"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s。輕觸即可設為靜音,但系統可能會將無障礙服務一併設為靜音。"</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s。輕觸即可設為震動。"</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s。輕觸即可設為靜音。"</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"靜音"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"取消靜音"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"震動"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"新增"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"來自「<xliff:g id="APP">%s</xliff:g>」的建議"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"已更新控制項"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"裝置已鎖定"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN 碼含有字母或符號"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"驗證「<xliff:g id="DEVICE">%s</xliff:g>」"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN 碼錯誤"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 371702f..d4e05d0 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -412,7 +412,8 @@
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Kuze kube sekuphumeni kwelanga"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Kuvulwe ngo-<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Kuze kube ngu-<xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_reduce_bright_colors_label" msgid="4782053257950003419">"Nciphisa ukukhanya"</string>
+    <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
+    <skip />
     <string name="quick_settings_nfc_label" msgid="1054317416221168085">"I-NFC"</string>
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"I-NFC ikhutshaziwe"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"I-NFC inikwe amandla"</string>
@@ -446,6 +447,8 @@
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Vula ukuze usebenzise i-NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Le divayisi eyenhlangano yakho"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Le divayisi ngeye-<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
+    <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
+    <skip />
     <string name="phone_hint" msgid="6682125338461375925">"Swayiphela ifoni kusukela kusithonjana"</string>
     <string name="voice_hint" msgid="7476017460191291417">"Swayiphela isilekeleli sezwi kusukela kusithonjana"</string>
     <string name="camera_hint" msgid="4519495795000658637">"Swayiphela ikhamela kusukela kusithonjana"</string>
@@ -625,6 +628,8 @@
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Thepha ukuze uthulise. Amasevisi okufinyelela angathuliswa."</string>
     <string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Thepha ukuze usethele ekudlidlizeni."</string>
     <string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Thepha ukuze uthulise."</string>
+    <!-- no translation found for volume_ringer_change (3574969197796055532) -->
+    <skip />
     <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"thulisa"</string>
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"susa ukuthula"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"dlidliza"</string>
@@ -1038,6 +1043,7 @@
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Engeza"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Kuphakanyiswe ngu-<xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_dialog_confirmation" msgid="586517302736263447">"Izilawuli zibuyekeziwe"</string>
+    <string name="controls_tile_locked" msgid="731547768182831938">"Idivayisi ikhiyiwe"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Iphinikhodi iqukethe amaletha namasimbui"</string>
     <string name="controls_pin_verify" msgid="3452778292918877662">"Qinisekisa i-<xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Iphinikhodi engalungile"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index acd671c..3bc1c80 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -265,7 +265,6 @@
     <color name="control_enabled_cool_foreground">@color/GM2_blue_300</color>
     <color name="control_thumbnail_tint">#33000000</color>
     <color name="control_thumbnail_shadow_color">@*android:color/black</color>
-    <color name="controls_lockscreen_scrim">#AA000000</color>
 
     <!-- Docked misalignment message -->
     <color name="misalignment_text_color">#F28B82</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 13c0110..b75a0bc 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -312,7 +312,6 @@
         <item>com.android.systemui.accessibility.SystemActions</item>
         <item>com.android.systemui.toast.ToastUI</item>
         <item>com.android.systemui.wmshell.WMShell</item>
-        <item>com.android.systemui.people.widget.PeopleSpaceWidgetEnabler</item>
     </string-array>
 
     <!-- QS tile shape store width. negative implies fill configuration instead of stroke-->
@@ -413,6 +412,9 @@
     <!-- Whether or not child notifications that are part of a group will have shadows. -->
     <bool name="config_enableShadowOnChildNotifications">true</bool>
 
+    <!-- If true, group numbers are shown in the expander instead of via "+N" overflow number -->
+    <bool name="config_showNotificationGroupCountInExpander">true</bool>
+
     <!-- Whether or not a view containing child notifications will have a custom background when
          it has been expanded to reveal its children. -->
     <bool name="config_showGroupNotificationBgWhenExpanded">false</bool>
@@ -421,6 +423,9 @@
      vibrator is capable of subtle vibrations -->
     <bool name="config_vibrateOnIconAnimation">false</bool>
 
+    <!-- Adjust the theme on fully custom and decorated custom view notifications -->
+    <bool name="config_adjustThemeOnNotificationCustomViews">false</bool>
+
     <!-- If true, enable the advance anti-falsing classifier on the lockscreen. On some devices it
          does not work well, particularly with noisy touchscreens. Note that disabling it may
          increase the rate of unintentional unlocks. -->
@@ -574,4 +579,7 @@
 
     <!-- Whether to use the split 2-column notification shade -->
     <bool name="config_use_split_notification_shade">false</bool>
+
+    <!-- Determines whether the shell features all run on another thread. -->
+    <bool name="config_enableShellMainThread">false</bool>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 89c849a..ea0ea5e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -456,10 +456,12 @@
 
     <dimen name="volume_dialog_panel_transparent_padding">20dp</dimen>
 
-    <dimen name="volume_dialog_stream_padding">8dp</dimen>
+    <dimen name="volume_dialog_stream_padding">12dp</dimen>
 
     <dimen name="volume_dialog_panel_width">64dp</dimen>
 
+    <dimen name="volume_dialog_panel_width_half">32dp</dimen>
+
     <dimen name="volume_dialog_slider_height">116dp</dimen>
 
     <dimen name="volume_dialog_ringer_size">64dp</dimen>
@@ -486,6 +488,13 @@
 
     <dimen name="volume_tool_tip_arrow_corner_radius">2dp</dimen>
 
+    <!-- Size of each item in the ringer selector drawer. -->
+    <dimen name="volume_ringer_drawer_item_size">64dp</dimen>
+    <dimen name="volume_ringer_drawer_item_size_half">32dp</dimen>
+
+    <!-- Size of the icon inside each item in the ringer selector drawer. -->
+    <dimen name="volume_ringer_drawer_icon_size">24dp</dimen>
+
     <!-- Gravity for the notification panel -->
     <integer name="notification_panel_layout_gravity">0x31</integer><!-- center_horizontal|top -->
 
@@ -966,7 +975,7 @@
     <dimen name="volume_row_padding_start">4dp</dimen>
     <dimen name="volume_row_header_padding_start">16dp</dimen>
     <dimen name="volume_row_height">64dp</dimen>
-    <dimen name="volume_row_slider_height">48dp</dimen>
+    <dimen name="volume_row_slider_height">192dp</dimen>
     <dimen name="volume_row_slider_padding_start">12dp</dimen>
 
     <dimen name="volume_expander_margin_end">2dp</dimen>
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index 3e16cd4..e551892 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -44,4 +44,6 @@
     <bool name="flag_toast_style">false</bool>
 
     <bool name="flag_navigation_bar_overlay">false</bool>
+
+    <bool name="flag_pm_lite">false</bool>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index e066bce..5f8df5a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1054,6 +1054,9 @@
     <!-- Text on keyguard screen and in Quick Settings footer indicating that user's device belongs to their organization. [CHAR LIMIT=40] -->
     <string name="do_disclosure_with_name">This device belongs to <xliff:g id="organization_name" example="Foo, Inc.">%s</xliff:g></string>
 
+    <!-- Text on keyguard screen and in Quick Settings footer indicating that the user's device is provided by the Creditor. [CHAR LIMIT=60] -->
+    <string name="do_financed_disclosure_with_name">This device is provided by <xliff:g id="organization_name" example="Foo, Inc.">%s</xliff:g></string>
+
     <!-- Shows when people have clicked on the phone icon [CHAR LIMIT=60] -->
     <string name="phone_hint">Swipe from icon for phone</string>
 
@@ -1558,6 +1561,8 @@
     <string name="volume_stream_content_description_vibrate_a11y">%1$s. Tap to set to vibrate.</string>
     <string name="volume_stream_content_description_mute_a11y">%1$s. Tap to mute.</string>
 
+    <string name="volume_ringer_change">Tap to change ringer mode</string>
+
     <!-- Hint for accessibility. For example: double tap to mute [CHAR_LIMIT=NONE] -->
     <string name="volume_ringer_hint_mute">mute</string>
     <!-- Hint for accessibility. For example: double tap to unmute [CHAR_LIMIT=NONE] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 14b376a..2d202fb 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -663,16 +663,16 @@
     </style>
 
     <style name="Theme.SystemUI.Dialog.Control.LockScreen" parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar">
-      <item name="android:windowAnimationStyle">@style/Animation.Fade</item>
+      <item name="android:windowAnimationStyle">@style/Animation.ControlDialog</item>
       <item name="android:windowFullscreen">true</item>
       <item name="android:windowIsFloating">false</item>
-      <item name="android:windowBackground">@color/controls_lockscreen_scrim</item>
+      <item name="android:windowBackground">@null</item>
       <item name="android:backgroundDimEnabled">true</item>
     </style>
 
-    <style name="Animation.Fade">
-      <item name="android:windowEnterAnimation">@android:anim/fade_in</item>
-      <item name="android:windowExitAnimation">@android:anim/fade_out</item>
+    <style name="Animation.ControlDialog">
+      <item name="android:windowEnterAnimation">@*android:anim/dialog_enter</item>
+      <item name="android:windowExitAnimation">@*android:anim/dialog_exit</item>
     </style>
 
     <style name="Control" />
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
index d2698ee..b3a29a3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
@@ -190,7 +190,7 @@
         }
 
         @Override
-        public void onActivityDismissingDockedStack() {
+        public void onActivityDismissingDockedTask() {
             mHandler.sendEmptyMessage(ON_ACTIVITY_DISMISSING_DOCKED_STACK);
         }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 5f6fd30..a2d7707 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -29,12 +29,17 @@
 import android.content.Context;
 import android.graphics.Insets;
 import android.graphics.Rect;
+import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.MathUtils;
 import android.util.TypedValue;
+import android.view.Gravity;
 import android.view.MotionEvent;
+import android.view.OrientationEventListener;
 import android.view.VelocityTracker;
+import android.view.View;
 import android.view.ViewConfiguration;
+import android.view.ViewPropertyAnimator;
 import android.view.WindowInsets;
 import android.view.WindowInsetsAnimation;
 import android.view.WindowInsetsAnimationControlListener;
@@ -55,6 +60,7 @@
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 
 import java.util.List;
 
@@ -99,6 +105,12 @@
     private boolean mDisappearAnimRunning;
     private SwipeListener mSwipeListener;
 
+    private boolean mIsSecurityViewLeftAligned = true;
+    private boolean mOneHandedMode = false;
+    private SecurityMode mSecurityMode = SecurityMode.Invalid;
+    private ViewPropertyAnimator mRunningOneHandedAnimator;
+    private final OrientationEventListener mOrientationEventListener;
+
     private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback =
             new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {
 
@@ -157,16 +169,20 @@
     // Used to notify the container when something interesting happens.
     public interface SecurityCallback {
         boolean dismiss(boolean authenticated, int targetUserId, boolean bypassSecondaryLockScreen);
+
         void userActivity();
+
         void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
 
         /**
-         * @param strongAuth wheher the user has authenticated with strong authentication like
-         *                   pattern, password or PIN but not by trust agents or fingerprint
+         * @param strongAuth   wheher the user has authenticated with strong authentication like
+         *                     pattern, password or PIN but not by trust agents or fingerprint
          * @param targetUserId a user that needs to be the foreground user at the finish completion.
          */
         void finish(boolean strongAuth, int targetUserId);
+
         void reset();
+
         void onCancelClicked();
     }
 
@@ -224,12 +240,136 @@
         super(context, attrs, defStyle);
         mSpringAnimation = new SpringAnimation(this, DynamicAnimation.Y);
         mViewConfiguration = ViewConfiguration.get(context);
+
+        mOrientationEventListener = new OrientationEventListener(context) {
+            @Override
+            public void onOrientationChanged(int orientation) {
+                updateLayoutForSecurityMode(mSecurityMode);
+            }
+        };
     }
 
     void onResume(SecurityMode securityMode, boolean faceAuthEnabled) {
+        mSecurityMode = securityMode;
         mSecurityViewFlipper.setWindowInsetsAnimationCallback(mWindowInsetsAnimationCallback);
         updateBiometricRetry(securityMode, faceAuthEnabled);
 
+        updateLayoutForSecurityMode(securityMode);
+        mOrientationEventListener.enable();
+    }
+
+    void updateLayoutForSecurityMode(SecurityMode securityMode) {
+        mSecurityMode = securityMode;
+        mOneHandedMode = canUseOneHandedBouncer();
+
+        if (mOneHandedMode) {
+            mIsSecurityViewLeftAligned = isOneHandedKeyguardLeftAligned(mContext);
+        }
+
+        updateSecurityViewGravity();
+        updateSecurityViewLocation(false);
+    }
+
+    /** Return whether the one-handed keyguard should be enabled. */
+    private boolean canUseOneHandedBouncer() {
+        // Is it enabled?
+        if (!getResources().getBoolean(
+                com.android.internal.R.bool.config_enableOneHandedKeyguard)) {
+            return false;
+        }
+
+        if (!KeyguardSecurityModel.isSecurityViewOneHanded(mSecurityMode)) {
+            return false;
+        }
+
+        return getResources().getBoolean(R.bool.can_use_one_handed_bouncer);
+    }
+
+    /** Read whether the one-handed keyguard should be on the left/right from settings. */
+    private boolean isOneHandedKeyguardLeftAligned(Context context) {
+        try {
+            return Settings.Global.getInt(context.getContentResolver(),
+                    Settings.Global.ONE_HANDED_KEYGUARD_SIDE)
+                    == Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT;
+        } catch (Settings.SettingNotFoundException ex) {
+            return true;
+        }
+    }
+
+    private void updateSecurityViewGravity() {
+        View securityView = findKeyguardSecurityView();
+
+        if (securityView == null) {
+            return;
+        }
+
+        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) securityView.getLayoutParams();
+
+        if (mOneHandedMode) {
+            lp.gravity = Gravity.LEFT | Gravity.BOTTOM;
+        } else {
+            lp.gravity = Gravity.CENTER_HORIZONTAL;
+        }
+
+        securityView.setLayoutParams(lp);
+    }
+
+    /**
+     * Moves the inner security view to the correct location (in one handed mode) with animation.
+     * This is triggered when the user taps on the side of the screen that is not currently occupied
+     * by the security view .
+     */
+    private void updateSecurityViewLocation(boolean animate) {
+        View securityView = findKeyguardSecurityView();
+
+        if (securityView == null) {
+            return;
+        }
+
+        if (!mOneHandedMode) {
+            securityView.setTranslationX(0);
+            return;
+        }
+
+        if (mRunningOneHandedAnimator != null) {
+            mRunningOneHandedAnimator.cancel();
+            mRunningOneHandedAnimator = null;
+        }
+
+        int targetTranslation = mIsSecurityViewLeftAligned ? 0 : (int) (getMeasuredWidth() / 2f);
+
+        if (animate) {
+            mRunningOneHandedAnimator = securityView.animate().translationX(targetTranslation);
+            mRunningOneHandedAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+            mRunningOneHandedAnimator.setListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mRunningOneHandedAnimator = null;
+                }
+            });
+
+            mRunningOneHandedAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+            mRunningOneHandedAnimator.start();
+        } else {
+            securityView.setTranslationX(targetTranslation);
+        }
+    }
+
+    @Nullable
+    private KeyguardSecurityViewFlipper findKeyguardSecurityView() {
+        for (int i = 0; i < getChildCount(); i++) {
+            View child = getChildAt(i);
+
+            if (isKeyguardSecurityView(child)) {
+                return (KeyguardSecurityViewFlipper) child;
+            }
+        }
+
+        return null;
+    }
+
+    private boolean isKeyguardSecurityView(View view) {
+        return view instanceof KeyguardSecurityViewFlipper;
     }
 
     public void onPause() {
@@ -238,6 +378,7 @@
             mAlertDialog = null;
         }
         mSecurityViewFlipper.setWindowInsetsAnimationCallback(null);
+        mOrientationEventListener.disable();
     }
 
     @Override
@@ -319,19 +460,44 @@
                 if (mSwipeListener != null) {
                     mSwipeListener.onSwipeUp();
                 }
+            } else {
+                if (!mIsDragging) {
+                    handleTap(event);
+                }
             }
         }
         return true;
     }
 
+    private void handleTap(MotionEvent event) {
+        // If we're using a fullscreen security mode, skip
+        if (!mOneHandedMode) {
+            return;
+        }
+
+        // Did the tap hit the "other" side of the bouncer?
+        if ((mIsSecurityViewLeftAligned && (event.getX() > getWidth() / 2f))
+                || (!mIsSecurityViewLeftAligned && (event.getX() < getWidth() / 2f))) {
+            mIsSecurityViewLeftAligned = !mIsSecurityViewLeftAligned;
+
+            Settings.Global.putInt(
+                    mContext.getContentResolver(),
+                    Settings.Global.ONE_HANDED_KEYGUARD_SIDE,
+                    mIsSecurityViewLeftAligned ? Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT
+                            : Settings.Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT);
+
+            updateSecurityViewLocation(true);
+        }
+    }
+
     void setSwipeListener(SwipeListener swipeListener) {
         mSwipeListener = swipeListener;
     }
 
     private void startSpringAnimation(float startVelocity) {
         mSpringAnimation
-            .setStartVelocity(startVelocity)
-            .animateToFinalPosition(0);
+                .setStartVelocity(startVelocity)
+                .animateToFinalPosition(0);
     }
 
     public void startDisappearAnimation(SecurityMode securitySelection) {
@@ -441,18 +607,17 @@
         return insets.inset(0, 0, 0, inset);
     }
 
-
     private void showDialog(String title, String message) {
         if (mAlertDialog != null) {
             mAlertDialog.dismiss();
         }
 
         mAlertDialog = new AlertDialog.Builder(mContext)
-            .setTitle(title)
-            .setMessage(message)
-            .setCancelable(false)
-            .setNeutralButton(R.string.ok, null)
-            .create();
+                .setTitle(title)
+                .setMessage(message)
+                .setCancelable(false)
+                .setNeutralButton(R.string.ok, null)
+                .create();
         if (!(mContext instanceof Activity)) {
             mAlertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
         }
@@ -490,6 +655,47 @@
         }
     }
 
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int maxHeight = 0;
+        int maxWidth = 0;
+        int childState = 0;
+
+        int halfWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
+                MeasureSpec.getSize(widthMeasureSpec) / 2,
+                MeasureSpec.getMode(widthMeasureSpec));
+
+        for (int i = 0; i < getChildCount(); i++) {
+            final View view = getChildAt(i);
+            if (view.getVisibility() != GONE) {
+                if (mOneHandedMode && isKeyguardSecurityView(view)) {
+                    measureChildWithMargins(view, halfWidthMeasureSpec, 0,
+                            heightMeasureSpec, 0);
+                } else {
+                    measureChildWithMargins(view, widthMeasureSpec, 0,
+                            heightMeasureSpec, 0);
+                }
+                final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+                maxWidth = Math.max(maxWidth,
+                        view.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
+                maxHeight = Math.max(maxHeight,
+                        view.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
+                childState = combineMeasuredStates(childState, view.getMeasuredState());
+            }
+        }
+
+        maxWidth += getPaddingLeft() + getPaddingRight();
+        maxHeight += getPaddingTop() + getPaddingBottom();
+
+        // Check against our minimum height and width
+        maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
+        maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
+
+        setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
+                resolveSizeAndState(maxHeight, heightMeasureSpec,
+                        childState << MEASURED_HEIGHT_STATE_SHIFT));
+    }
+
     void showAlmostAtWipeDialog(int attempts, int remaining, int userType) {
         String message = null;
         switch (userType) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 1a8d420..fdab8db 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -404,6 +404,7 @@
         if (newView != null) {
             newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
             mSecurityViewFlipperController.show(newView);
+            mView.updateLayoutForSecurityMode(securityMode);
         }
 
         mSecurityCallback.onSecurityModeChanged(
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
index c77c867..631c248 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -92,4 +92,13 @@
                 throw new IllegalStateException("Unknown security quality:" + security);
         }
     }
+
+    /**
+     * Returns whether the given security view should be used in a "one handed" way. This can be
+     * used to change how the security view is drawn (e.g. take up less of the screen, and align to
+     * one side).
+     */
+    public static boolean isSecurityViewOneHanded(SecurityMode securityMode) {
+        return securityMode == SecurityMode.Pattern || securityMode == SecurityMode.PIN;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index d9a1eb6..a4054be 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -305,6 +305,7 @@
     private boolean mLogoutEnabled;
     // cached value to avoid IPCs
     private boolean mIsUdfpsEnrolled;
+    private boolean mKeyguardQsUserSwitchEnabled;
     // If the user long pressed the lock icon, disabling face auth for the current session.
     private boolean mLockIconPressed;
     private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -1916,7 +1917,7 @@
             return isFaceAuthEnabledForUser(KeyguardUpdateMonitor.getCurrentUser())
                     && !isUdfpsEnrolled();
         }
-        return true;
+        return !isKeyguardQsUserSwitchEnabled();
     }
 
     /**
@@ -1926,6 +1927,17 @@
         return mIsUdfpsEnrolled;
     }
 
+    /**
+     * @return true if the keyguard qs user switcher shortcut is enabled
+     */
+    public boolean isKeyguardQsUserSwitchEnabled() {
+        return mKeyguardQsUserSwitchEnabled;
+    }
+
+    public void setKeyguardQsUserSwitchEnabled(boolean enabled) {
+        mKeyguardQsUserSwitchEnabled = enabled;
+    }
+
     private final UserSwitchObserver mUserSwitchObserver = new UserSwitchObserver() {
         @Override
         public void onUserSwitching(int newUserId, IRemoteCallback reply) {
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
index 8cb1bc4..5db3349 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
@@ -69,7 +69,9 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent event) {
-        if (mAnimator != null) mAnimator.start();
+        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+            if (mAnimator != null) mAnimator.start();
+        }
         return super.onTouchEvent(event);
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index a4a781d..e6a9d4f 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -160,10 +160,9 @@
     public boolean onTouchEvent(MotionEvent event) {
         if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
             doHapticKeyClick();
+            if (mAnimator != null) mAnimator.start();
         }
 
-        if (mAnimator != null) mAnimator.start();
-
         return super.onTouchEvent(event);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index fe0ae33..ae4c8e5 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -59,6 +59,7 @@
 import com.android.systemui.power.EnhancedEstimates;
 import com.android.systemui.power.PowerUI;
 import com.android.systemui.privacy.PrivacyItemController;
+import com.android.systemui.qs.ReduceBrightColorsController;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.screenrecord.RecordingController;
@@ -246,6 +247,7 @@
     @Inject Lazy<KeyguardUpdateMonitor> mKeyguardUpdateMonitor;
     @Inject Lazy<BatteryController> mBatteryController;
     @Inject Lazy<NightDisplayListener> mNightDisplayListener;
+    @Inject Lazy<ReduceBrightColorsController> mReduceBrightColorsController;
     @Inject Lazy<ManagedProfileController> mManagedProfileController;
     @Inject Lazy<NextAlarmController> mNextAlarmController;
     @Inject Lazy<DataSaverController> mDataSaverController;
@@ -393,6 +395,8 @@
 
         mProviders.put(NightDisplayListener.class, mNightDisplayListener::get);
 
+        mProviders.put(ReduceBrightColorsController.class, mReduceBrightColorsController::get);
+
         mProviders.put(ManagedProfileController.class, mManagedProfileController::get);
 
         mProviders.put(NextAlarmController.class, mNextAlarmController::get);
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 865ca40..59c0fb8 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -19,15 +19,18 @@
 import android.app.ActivityThread;
 import android.app.Application;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.os.Process;
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.Log;
 import android.util.TimingsTraceLog;
 import android.view.SurfaceControl;
@@ -37,6 +40,8 @@
 import com.android.systemui.dagger.GlobalRootComponent;
 import com.android.systemui.dagger.SysUIComponent;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.people.PeopleSpaceActivity;
+import com.android.systemui.people.widget.PeopleSpaceWidgetProvider;
 import com.android.systemui.shared.system.ThreadedRendererCompat;
 import com.android.systemui.util.NotificationChannels;
 
@@ -121,6 +126,26 @@
                             mServices[i].onBootCompleted();
                         }
                     }
+                    // If SHOW_PEOPLE_SPACE is true, enable People Space widget provider.
+                    // TODO(b/170396074): Migrate to new feature flag (go/silk-flags-howto)
+                    try {
+                        int showPeopleSpace = Settings.Global.getInt(context.getContentResolver(),
+                                Settings.Global.SHOW_PEOPLE_SPACE, 1);
+                        context.getPackageManager().setComponentEnabledSetting(
+                                new ComponentName(context, PeopleSpaceWidgetProvider.class),
+                                showPeopleSpace == 1
+                                        ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+                                        : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+                                PackageManager.DONT_KILL_APP);
+                        context.getPackageManager().setComponentEnabledSetting(
+                                new ComponentName(context, PeopleSpaceActivity.class),
+                                showPeopleSpace == 1
+                                        ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+                                        : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+                                PackageManager.DONT_KILL_APP);
+                    } catch (Exception e) {
+                        Log.w(TAG, "Error enabling People Space widget:", e);
+                    }
                 }
             }, bootCompletedFilter);
 
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 19520df..9d00262 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -115,7 +115,8 @@
                     .setShellCommandHandler(mWMComponent.getShellCommandHandler())
                     .setAppPairs(mWMComponent.getAppPairs())
                     .setTaskViewFactory(mWMComponent.getTaskViewFactory())
-                    .setTransitions(mWMComponent.getTransitions());
+                    .setTransitions(mWMComponent.getTransitions())
+                    .setStartingSurface(mWMComponent.getStartingSurface());
         } else {
             // TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option
             // is separating this logic into newly creating SystemUITestsFactory.
@@ -129,7 +130,8 @@
                     .setShellCommandHandler(Optional.ofNullable(null))
                     .setAppPairs(Optional.ofNullable(null))
                     .setTaskViewFactory(Optional.ofNullable(null))
-                    .setTransitions(Transitions.createEmptyForTesting());
+                    .setTransitions(Transitions.createEmptyForTesting())
+                    .setStartingSurface(Optional.ofNullable(null));
         }
         mSysUIComponent = builder.build();
         if (initializeComponents) {
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index 9686c91f..2040347 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -16,8 +16,8 @@
 
 package com.android.systemui.appops;
 
-import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_CAMERA;
-import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE;
+import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
+import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE;
 import static android.media.AudioManager.ACTION_MICROPHONE_MUTE_CHANGED;
 
 import android.Manifest;
@@ -40,6 +40,7 @@
 
 import androidx.annotation.WorkerThread;
 
+import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dumpable;
@@ -78,6 +79,7 @@
     private static final boolean DEBUG = false;
 
     private final BroadcastDispatcher mDispatcher;
+    private final Context mContext;
     private final AppOpsManager mAppOps;
     private final AudioManager mAudioManager;
     private final LocationManager mLocationManager;
@@ -137,10 +139,11 @@
         mAudioManager = audioManager;
         mSensorPrivacyController = sensorPrivacyController;
         mMicMuted = audioManager.isMicrophoneMute()
-                || mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_MICROPHONE);
-        mCameraDisabled = mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_CAMERA);
+                || mSensorPrivacyController.isSensorBlocked(MICROPHONE);
+        mCameraDisabled = mSensorPrivacyController.isSensorBlocked(CAMERA);
         mLocationManager = context.getSystemService(LocationManager.class);
         mPackageManager = context.getPackageManager();
+        mContext = context;
         dumpManager.registerDumpable(TAG, this);
     }
 
@@ -159,8 +162,8 @@
             mSensorPrivacyController.addCallback(this);
 
             mMicMuted = mAudioManager.isMicrophoneMute()
-                    || mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_MICROPHONE);
-            mCameraDisabled = mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_CAMERA);
+                    || mSensorPrivacyController.isSensorBlocked(MICROPHONE);
+            mCameraDisabled = mSensorPrivacyController.isSensorBlocked(CAMERA);
 
             mBGHandler.post(() -> mAudioRecordingCallback.onRecordingConfigChanged(
                     mAudioManager.getActiveRecordingConfigurations()));
@@ -357,6 +360,15 @@
         return mLocationProviderPackages.contains(packageName);
     }
 
+    private boolean isSpeechRecognizerUsage(int opCode, String packageName) {
+        if (AppOpsManager.OP_RECORD_AUDIO != opCode) {
+            return false;
+        }
+
+        return packageName.equals(
+                mContext.getString(R.string.config_systemSpeechRecognizer));
+    }
+
     // TODO ntmyren: remove after teamfood is finished
     private boolean shouldShowAppPredictor(String pkgName) {
         if (!DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, "permissions_hub_2_enabled",
@@ -388,7 +400,8 @@
         }
         // TODO ntmyren: Replace this with more robust check if this moves beyond teamfood
         if ((appOpCode == AppOpsManager.OP_CAMERA && isLocationProvider(packageName))
-                || shouldShowAppPredictor(packageName)) {
+                || shouldShowAppPredictor(packageName)
+                || isSpeechRecognizerUsage(appOpCode, packageName)) {
             return true;
         }
 
@@ -583,16 +596,16 @@
     @Override
     public void onReceive(Context context, Intent intent) {
         mMicMuted = mAudioManager.isMicrophoneMute()
-                || mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_MICROPHONE);
+                || mSensorPrivacyController.isSensorBlocked(MICROPHONE);
         updateSensorDisabledStatus();
     }
 
     @Override
     public void onSensorBlockedChanged(int sensor, boolean blocked) {
         mBGHandler.post(() -> {
-            if (sensor == INDIVIDUAL_SENSOR_CAMERA) {
+            if (sensor == CAMERA) {
                 mCameraDisabled = blocked;
-            } else if (sensor == INDIVIDUAL_SENSOR_MICROPHONE) {
+            } else if (sensor == MICROPHONE) {
                 mMicMuted = mAudioManager.isMicrophoneMute() || blocked;
             }
             updateSensorDisabledStatus();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java
index 3bf75d1..a029003 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java
@@ -31,15 +31,18 @@
  * sensor area.
  */
 public abstract class UdfpsAnimation extends Drawable {
-    abstract void updateColor();
+    protected abstract void updateColor();
+    protected abstract void onDestroy();
 
     @NonNull protected final Context mContext;
     @NonNull protected final Drawable mFingerprintDrawable;
     @Nullable private View mView;
+    private boolean mIlluminationShowing;
 
     public UdfpsAnimation(@NonNull Context context) {
         mContext = context;
         mFingerprintDrawable = context.getResources().getDrawable(R.drawable.ic_fingerprint, null);
+        mFingerprintDrawable.mutate();
     }
 
     public void onSensorRectUpdated(@NonNull RectF sensorRect) {
@@ -60,6 +63,14 @@
         mView = view;
     }
 
+    boolean isIlluminationShowing() {
+        return mIlluminationShowing;
+    }
+
+    void setIlluminationShowing(boolean showing) {
+        mIlluminationShowing = showing;
+    }
+
     /**
      * @return The amount of padding that's needed on each side of the sensor, in pixels.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java
index 5290986..28b5719 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java
@@ -58,11 +58,16 @@
     }
 
     @Override
-    void updateColor() {
+    protected void updateColor() {
         mFingerprintDrawable.setTint(mContext.getColor(R.color.udfps_enroll_icon));
     }
 
     @Override
+    protected void onDestroy() {
+
+    }
+
+    @Override
     public void onSensorRectUpdated(@NonNull RectF sensorRect) {
         super.onSensorRectUpdated(sensorRect);
         mSensorRect = sensorRect;
@@ -70,6 +75,10 @@
 
     @Override
     public void draw(@NonNull Canvas canvas) {
+        if (isIlluminationShowing()) {
+            return;
+        }
+
         final boolean isNightMode = (mContext.getResources().getConfiguration().uiMode
                 & Configuration.UI_MODE_NIGHT_YES) != 0;
         if (!isNightMode) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationFpmOther.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationFpmOther.java
index efc864a..ef7a340 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationFpmOther.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationFpmOther.java
@@ -34,12 +34,21 @@
     }
 
     @Override
-    void updateColor() {
+    protected void updateColor() {
+
+    }
+
+    @Override
+    protected void onDestroy() {
 
     }
 
     @Override
     public void draw(@NonNull Canvas canvas) {
+        if (isIlluminationShowing()) {
+            return;
+        }
+
         mFingerprintDrawable.draw(canvas);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationKeyguard.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationKeyguard.java
index 8664e44..5f268cf 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationKeyguard.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationKeyguard.java
@@ -42,6 +42,7 @@
     private static final String TAG = "UdfpsAnimationKeyguard";
 
     @NonNull private final Context mContext;
+    @NonNull private final StatusBarStateController mStatusBarStateController;
     private final int mMaxBurnInOffsetX;
     private final int mMaxBurnInOffsetY;
 
@@ -54,6 +55,7 @@
             @NonNull StatusBarStateController statusBarStateController) {
         super(context);
         mContext = context;
+        mStatusBarStateController = statusBarStateController;
 
         mMaxBurnInOffsetX = context.getResources()
                 .getDimensionPixelSize(R.dimen.udfps_burn_in_offset_x);
@@ -89,6 +91,10 @@
 
     @Override
     public void draw(@NonNull Canvas canvas) {
+        if (isIlluminationShowing()) {
+            return;
+        }
+
         canvas.save();
         canvas.translate(mBurnInOffsetX, mBurnInOffsetY);
         mFingerprintDrawable.draw(canvas);
@@ -106,11 +112,16 @@
     }
 
     @Override
-    public void updateColor() {
+    protected void updateColor() {
         final int lockScreenIconColor = Utils.getColorAttrDefaultColor(mContext,
                 R.attr.wallpaperTextColor);
         final int ambientDisplayIconColor = Color.WHITE;
         mFingerprintDrawable.setTint(ColorUtils.blendARGB(lockScreenIconColor,
                 ambientDisplayIconColor, mInterpolatedDarkAmount));
     }
+
+    @Override
+    protected void onDestroy() {
+        mStatusBarStateController.removeCallback(this);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
index 44122cb..f4dd181 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
@@ -22,41 +22,49 @@
 import android.graphics.Canvas;
 import android.graphics.RectF;
 import android.util.AttributeSet;
-import android.view.View;
+import android.widget.FrameLayout;
 
 import com.android.systemui.doze.DozeReceiver;
 import com.android.systemui.statusbar.phone.StatusBar;
 
 /**
- * Class that coordinates non-HBM animations (such as enroll, keyguard, BiometricPrompt,
- * FingerprintManager).
+ * Base class for views containing UDFPS animations. Note that this is a FrameLayout so that we
+ * can support multiple child views drawing on the same region around the sensor location.
  */
-public class UdfpsAnimationView extends View implements DozeReceiver,
+public abstract class UdfpsAnimationView extends FrameLayout implements DozeReceiver,
         StatusBar.ExpansionChangedListener {
 
     private static final String TAG = "UdfpsAnimationView";
 
+    @Nullable protected abstract UdfpsAnimation getUdfpsAnimation();
+
     @NonNull private UdfpsView mParent;
-    @Nullable private UdfpsAnimation mUdfpsAnimation;
     @NonNull private RectF mSensorRect;
     private int mAlpha;
 
     public UdfpsAnimationView(Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
         mSensorRect = new RectF();
+        setWillNotDraw(false);
     }
 
     @Override
     protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
 
-        if (mUdfpsAnimation != null) {
+        if (getUdfpsAnimation() != null) {
             final int alpha = mParent.shouldPauseAuth() ? mAlpha : 255;
-            mUdfpsAnimation.setAlpha(alpha);
-            mUdfpsAnimation.draw(canvas);
+            getUdfpsAnimation().setAlpha(alpha);
+            getUdfpsAnimation().draw(canvas);
         }
     }
 
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        getUdfpsAnimation().onDestroy();
+    }
+
     private int expansionToAlpha(float expansion) {
         // Fade to 0 opacity when reaching this expansion amount
         final float maxExpansion = 0.4f;
@@ -69,38 +77,38 @@
         return (int) ((1 - percent) * 255);
     }
 
+    void onIlluminationStarting() {
+        getUdfpsAnimation().setIlluminationShowing(true);
+        postInvalidate();
+    }
+
+    void onIlluminationStopped() {
+        getUdfpsAnimation().setIlluminationShowing(false);
+        postInvalidate();
+    }
+
     void setParent(@NonNull UdfpsView parent) {
         mParent = parent;
     }
 
-    void setAnimation(@Nullable UdfpsAnimation animation) {
-        if (mUdfpsAnimation != null) {
-            mUdfpsAnimation.setAnimationView(null);
-        }
-
-        mUdfpsAnimation = animation;
-        if (mUdfpsAnimation != null) {
-            mUdfpsAnimation.setAnimationView(this);
-        }
-    }
-
     void onSensorRectUpdated(@NonNull RectF sensorRect) {
         mSensorRect = sensorRect;
-        if (mUdfpsAnimation != null) {
-            mUdfpsAnimation.onSensorRectUpdated(mSensorRect);
+        if (getUdfpsAnimation() != null) {
+            getUdfpsAnimation().onSensorRectUpdated(mSensorRect);
         }
     }
 
     void updateColor() {
-        if (mUdfpsAnimation != null) {
-            mUdfpsAnimation.updateColor();
+        if (getUdfpsAnimation() != null) {
+            getUdfpsAnimation().updateColor();
         }
+        postInvalidate();
     }
 
     @Override
     public void dozeTimeTick() {
-        if (mUdfpsAnimation instanceof DozeReceiver) {
-            ((DozeReceiver) mUdfpsAnimation).dozeTimeTick();
+        if (getUdfpsAnimation() instanceof DozeReceiver) {
+            ((DozeReceiver) getUdfpsAnimation()).dozeTimeTick();
         }
     }
 
@@ -111,16 +119,16 @@
     }
 
     public int getPaddingX() {
-        if (mUdfpsAnimation == null) {
+        if (getUdfpsAnimation() == null) {
             return 0;
         }
-        return mUdfpsAnimation.getPaddingX();
+        return getUdfpsAnimation().getPaddingX();
     }
 
     public int getPaddingY() {
-        if (mUdfpsAnimation == null) {
+        if (getUdfpsAnimation() == null) {
             return 0;
         }
-        return mUdfpsAnimation.getPaddingY();
+        return getUdfpsAnimation().getPaddingY();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewEnroll.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewEnroll.java
new file mode 100644
index 0000000..19e77493
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewEnroll.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.systemui.biometrics;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+
+import com.android.systemui.R;
+
+/**
+ * Class that coordinates non-HBM animations during enrollment.
+ */
+public class UdfpsAnimationViewEnroll extends UdfpsAnimationView
+        implements UdfpsEnrollHelper.Listener {
+
+    private static final String TAG = "UdfpsAnimationViewEnroll";
+
+    @NonNull private UdfpsAnimation mUdfpsAnimation;
+    @NonNull private UdfpsProgressBar mProgressBar;
+    @Nullable private UdfpsEnrollHelper mEnrollHelper;
+
+    @NonNull
+    @Override
+    protected UdfpsAnimation getUdfpsAnimation() {
+        return mUdfpsAnimation;
+    }
+
+    public UdfpsAnimationViewEnroll(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        mUdfpsAnimation = new UdfpsAnimationEnroll(context);
+    }
+
+    public void setEnrollHelper(@NonNull UdfpsEnrollHelper helper) {
+        mEnrollHelper = helper;
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        mProgressBar = findViewById(R.id.progress_bar);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        if (mEnrollHelper == null) {
+            Log.e(TAG, "Enroll helper is null");
+            return;
+        }
+
+        if (mEnrollHelper.shouldShowProgressBar()) {
+            mProgressBar.setVisibility(View.VISIBLE);
+
+            // Only need enrollment updates if the progress bar is showing :)
+            mEnrollHelper.setListener(this);
+        }
+    }
+
+    @Override
+    public void onEnrollmentProgress(int remaining, int totalSteps) {
+        final int interpolatedProgress = mProgressBar.getMax()
+                * Math.max(0, totalSteps + 1 - remaining) / (totalSteps + 1);
+
+        mProgressBar.setProgress(interpolatedProgress, true);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewFpmOther.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewFpmOther.java
new file mode 100644
index 0000000..3d2f5a0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewFpmOther.java
@@ -0,0 +1,42 @@
+/*
+ * 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.biometrics;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import androidx.annotation.Nullable;
+
+/**
+ * Class that coordinates non-HBM animations during other usage of FingerprintManager (not
+ * including Keyguard).
+ */
+public class UdfpsAnimationViewFpmOther extends UdfpsAnimationView {
+
+    private final UdfpsAnimationFpmOther mAnimation;
+
+    public UdfpsAnimationViewFpmOther(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        mAnimation = new UdfpsAnimationFpmOther(context);
+    }
+
+    @Nullable
+    @Override
+    protected UdfpsAnimation getUdfpsAnimation() {
+        return mAnimation;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewKeyguard.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewKeyguard.java
new file mode 100644
index 0000000..7d0b3e5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewKeyguard.java
@@ -0,0 +1,49 @@
+/*
+ * 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.biometrics;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+
+/**
+ * Class that coordinates non-HBM animations during keyguard authentication.
+ */
+public class UdfpsAnimationViewKeyguard extends UdfpsAnimationView {
+    @Nullable private UdfpsAnimationKeyguard mAnimation;
+
+    public UdfpsAnimationViewKeyguard(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    void setStatusBarStateController(@NonNull StatusBarStateController statusBarStateController) {
+        if (mAnimation == null) {
+            mAnimation = new UdfpsAnimationKeyguard(getContext(), statusBarStateController);
+            mAnimation.setAnimationView(this);
+        }
+    }
+
+    @Nullable
+    @Override
+    protected UdfpsAnimation getUdfpsAnimation() {
+        return mAnimation;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 6451ad9..e1d7eb3 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -68,17 +68,17 @@
 
     private final Context mContext;
     private final FingerprintManager mFingerprintManager;
+    @NonNull private final LayoutInflater mInflater;
     private final WindowManager mWindowManager;
     private final DelayableExecutor mFgExecutor;
-    private final StatusBarStateController mStatusBarStateController;
+    @NonNull private final StatusBar mStatusBar;
+    @NonNull private final StatusBarStateController mStatusBarStateController;
     // 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;
     private final WindowManager.LayoutParams mCoreLayoutParams;
-    private final UdfpsView mView;
-    // Indicates whether the overlay is currently showing. Even if it has been requested, it might
-    // not be showing.
-    private boolean mIsOverlayShowing;
+
+    @Nullable private UdfpsView mView;
     // Indicates whether the overlay has been requested.
     private boolean mIsOverlayRequested;
     // Reason the overlay has been requested. See IUdfpsOverlayController for definitions.
@@ -111,20 +111,44 @@
 
         @Override
         public void onEnrollmentProgress(int sensorId, int remaining) {
-            mView.onEnrollmentProgress(remaining);
+            if (mEnrollHelper == null) {
+                Log.e(TAG, "onEnrollProgress received but helper is null");
+                return;
+            }
+            mEnrollHelper.onEnrollmentProgress(remaining);
         }
 
         @Override
         public void onEnrollmentHelp(int sensorId) {
-            mView.onEnrollmentHelp();
+            if (mEnrollHelper == null) {
+                Log.e(TAG, "onEnrollmentHelp received but helper is null");
+                return;
+            }
+            mEnrollHelper.onEnrollmentHelp();
         }
 
         @Override
         public void setDebugMessage(int sensorId, String message) {
+            if (mView == null) {
+                return;
+            }
             mView.setDebugMessage(message);
         }
     }
 
+    @VisibleForTesting
+    final StatusBar.ExpansionChangedListener mStatusBarExpansionListener =
+            (expansion, expanded) -> mView.onExpansionChanged(expansion, expanded);
+
+    @VisibleForTesting
+    final StatusBarStateController.StateListener mStatusBarStateListener =
+            new StatusBarStateController.StateListener() {
+                @Override
+                public void onStateChanged(int newState) {
+                        mView.onStateChanged(newState);
+                }
+    };
+
     @SuppressLint("ClickableViewAccessibility")
     private final UdfpsView.OnTouchListener mOnTouchListener = (v, event) -> {
         UdfpsView view = (UdfpsView) v;
@@ -157,18 +181,20 @@
     @Inject
     public UdfpsController(@NonNull Context context,
             @Main Resources resources,
-            LayoutInflater inflater,
+            @NonNull LayoutInflater inflater,
             @Nullable FingerprintManager fingerprintManager,
             WindowManager windowManager,
             @NonNull StatusBarStateController statusBarStateController,
             @Main DelayableExecutor fgExecutor,
-            @Nullable StatusBar statusBar) {
+            @NonNull StatusBar statusBar) {
         mContext = context;
+        mInflater = inflater;
         // The fingerprint manager is queried for UDFPS before this class is constructed, so the
         // fingerprint manager should never be null.
         mFingerprintManager = checkNotNull(fingerprintManager);
         mWindowManager = windowManager;
         mFgExecutor = fgExecutor;
+        mStatusBar = statusBar;
         mStatusBarStateController = statusBarStateController;
 
         mSensorProps = findFirstUdfps();
@@ -189,15 +215,7 @@
                 WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
         mCoreLayoutParams.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
 
-        mView = (UdfpsView) inflater.inflate(R.layout.udfps_view, null, false);
-        mView.setSensorProperties(mSensorProps);
-        mView.setHbmCallback(this);
-
-        statusBar.addExpansionChangedListener(mView);
-        statusBarStateController.addCallback(mView);
-
         mFingerprintManager.setUdfpsOverlayController(new UdfpsOverlayController());
-        mIsOverlayShowing = false;
     }
 
     @Nullable
@@ -220,7 +238,13 @@
      * @return where the UDFPS exists on the screen in pixels.
      */
     public RectF getSensorLocation() {
-        return mView.getSensorRect();
+        // This is currently used to calculate the amount of space available for notifications
+        // on lockscreen. Keyguard is only shown in portrait mode for now, so this will need to
+        // be updated if that ever changes.
+        return new RectF(mSensorProps.sensorLocationX - mSensorProps.sensorRadius,
+                mSensorProps.sensorLocationY - mSensorProps.sensorRadius,
+                mSensorProps.sensorLocationX + mSensorProps.sensorRadius,
+                mSensorProps.sensorLocationY + mSensorProps.sensorRadius);
     }
 
     private void showOverlay(int reason) {
@@ -249,7 +273,7 @@
         }
     }
 
-    private WindowManager.LayoutParams computeLayoutParams(@Nullable UdfpsAnimation animation) {
+    private WindowManager.LayoutParams computeLayoutParams(@Nullable UdfpsAnimationView animation) {
         final int paddingX = animation != null ? animation.getPaddingX() : 0;
         final int paddingY = animation != null ? animation.getPaddingY() : 0;
 
@@ -298,14 +322,24 @@
 
     private void showUdfpsOverlay(int reason) {
         mFgExecutor.execute(() -> {
-            if (!mIsOverlayShowing) {
+            if (mView == null) {
                 try {
                     Log.v(TAG, "showUdfpsOverlay | adding window");
-                    final UdfpsAnimation animation = getUdfpsAnimationForReason(reason);
-                    mView.setExtras(animation, mEnrollHelper);
+                    // TODO: Eventually we should refactor the code to inflate an
+                    //  operation-specific view here, instead of inflating a generic udfps_view
+                    //  and adding operation-specific animations to it.
+                    mView = (UdfpsView) mInflater.inflate(R.layout.udfps_view, null, false);
+                    mView.setSensorProperties(mSensorProps);
+                    mView.setHbmCallback(this);
+
+                    final UdfpsAnimationView animation = getUdfpsAnimationViewForReason(reason);
+                    mView.setAnimationView(animation);
+
+                    mStatusBar.addExpansionChangedListener(mStatusBarExpansionListener);
+                    mStatusBarStateController.addCallback(mStatusBarStateListener);
+
                     mWindowManager.addView(mView, computeLayoutParams(animation));
                     mView.setOnTouchListener(mOnTouchListener);
-                    mIsOverlayShowing = true;
                 } catch (RuntimeException e) {
                     Log.e(TAG, "showUdfpsOverlay | failed to add window", e);
                 }
@@ -315,17 +349,34 @@
         });
     }
 
-    @Nullable
-    private UdfpsAnimation getUdfpsAnimationForReason(int reason) {
+    @NonNull
+    private UdfpsAnimationView getUdfpsAnimationViewForReason(int reason) {
         Log.d(TAG, "getUdfpsAnimationForReason: " + reason);
+
+        final LayoutInflater inflater = LayoutInflater.from(mContext);
+
         switch (reason) {
             case IUdfpsOverlayController.REASON_ENROLL_FIND_SENSOR:
-            case IUdfpsOverlayController.REASON_ENROLL_ENROLLING:
-                return new UdfpsAnimationEnroll(mContext);
-            case IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD:
-                return new UdfpsAnimationKeyguard(mContext, mStatusBarStateController);
-            case IUdfpsOverlayController.REASON_AUTH_FPM_OTHER:
-                return new UdfpsAnimationFpmOther(mContext);
+            case IUdfpsOverlayController.REASON_ENROLL_ENROLLING: {
+                final UdfpsAnimationViewEnroll animation = (UdfpsAnimationViewEnroll)
+                        inflater.inflate(R.layout.udfps_animation_view_enroll, null, false);
+                animation.setEnrollHelper(mEnrollHelper);
+                return animation;
+            }
+
+            case IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD: {
+                final UdfpsAnimationViewKeyguard animation = (UdfpsAnimationViewKeyguard)
+                        inflater.inflate(R.layout.udfps_animation_view_keyguard, null, false);
+                animation.setStatusBarStateController(mStatusBarStateController);
+                return animation;
+            }
+
+            case IUdfpsOverlayController.REASON_AUTH_FPM_OTHER: {
+                final UdfpsAnimationViewFpmOther animation = (UdfpsAnimationViewFpmOther)
+                        inflater.inflate(R.layout.udfps_animation_view_fpm_other, null, false);
+                return animation;
+            }
+
             default:
                 Log.d(TAG, "Animation for reason " + reason + " not supported yet");
                 return null;
@@ -334,14 +385,16 @@
 
     private void hideUdfpsOverlay() {
         mFgExecutor.execute(() -> {
-            if (mIsOverlayShowing) {
+            if (mView != null) {
                 Log.v(TAG, "hideUdfpsOverlay | removing window");
-                mView.setExtras(null, null);
-                mView.setOnTouchListener(null);
                 // Reset the controller back to its starting state.
                 onFingerUp();
+
+                mStatusBar.removeExpansionChangedListener(mStatusBarExpansionListener);
+                mStatusBarStateController.removeCallback(mStatusBarStateListener);
+
                 mWindowManager.removeView(mView);
-                mIsOverlayShowing = false;
+                mView = null;
             } else {
                 Log.v(TAG, "hideUdfpsOverlay | the overlay is already hidden");
             }
@@ -388,12 +441,20 @@
 
     // This method can be called from the UI thread.
     private void onFingerDown(int x, int y, float minor, float major) {
+        if (mView == null) {
+            Log.w(TAG, "Null view in onFingerDown");
+            return;
+        }
         mView.startIllumination(() ->
                 mFingerprintManager.onPointerDown(mSensorProps.sensorId, x, y, minor, major));
     }
 
     // This method can be called from the UI thread.
     private void onFingerUp() {
+        if (mView == null) {
+            Log.w(TAG, "Null view in onFingerUp");
+            return;
+        }
         mFingerprintManager.onPointerUp(mSensorProps.sensorId);
         mView.stopIllumination();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
index 2442633..942fa7a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
@@ -16,22 +16,28 @@
 
 package com.android.systemui.biometrics;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.hardware.fingerprint.IUdfpsOverlayController;
 
-import androidx.annotation.NonNull;
-
 /**
  * Helps keep track of enrollment state and animates the progress bar accordingly.
  */
 public class UdfpsEnrollHelper {
     private static final String TAG = "UdfpsEnrollHelper";
 
+    interface Listener {
+        void onEnrollmentProgress(int remaining, int totalSteps);
+    }
+
     // IUdfpsOverlayController reason
     private final int mEnrollReason;
 
     private int mTotalSteps = -1;
     private int mCurrentProgress = 0;
 
+    @Nullable Listener mListener;
+
     public UdfpsEnrollHelper(int reason) {
         mEnrollReason = reason;
     }
@@ -40,21 +46,29 @@
         return mEnrollReason == IUdfpsOverlayController.REASON_ENROLL_ENROLLING;
     }
 
-    void onEnrollmentProgress(int remaining, @NonNull UdfpsProgressBar progressBar) {
+    void onEnrollmentProgress(int remaining) {
         if (mTotalSteps == -1) {
             mTotalSteps = remaining;
         }
 
-        mCurrentProgress = progressBar.getMax() * Math.max(0, mTotalSteps + 1 - remaining)
-                / (mTotalSteps + 1);
-        progressBar.setProgress(mCurrentProgress, true /* animate */);
-    }
-
-    void updateProgress(@NonNull UdfpsProgressBar progressBar) {
-        progressBar.setProgress(mCurrentProgress);
+        if (mListener != null) {
+            mListener.onEnrollmentProgress(remaining, mTotalSteps);
+        }
     }
 
     void onEnrollmentHelp() {
 
     }
+
+    void setListener(@NonNull Listener listener) {
+        mListener = listener;
+
+        // Only notify during setListener if enrollment is already in progress, so the progress
+        // bar can be updated. If enrollment has not started yet, the progress bar will be empty
+        // anyway.
+        if (mTotalSteps != -1) {
+            final int remainingSteps = mTotalSteps - mCurrentProgress;
+            mListener.onEnrollmentProgress(remainingSteps, mTotalSteps);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsSurfaceView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsSurfaceView.java
index 97c215e..61ec127 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsSurfaceView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsSurfaceView.java
@@ -52,6 +52,12 @@
     public UdfpsSurfaceView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
+        // Make this SurfaceView draw on top of everything else in this window. This allows us to
+        // 1) Always show the HBM circle on top of everything else, and
+        // 2) Properly composite this view with any other animations in the same window no matter
+        //    what contents are added in which order to this view hierarchy.
+        setZOrderOnTop(true);
+
         mHolder = getHolder();
         mHolder.setFormat(PixelFormat.RGBA_8888);
 
@@ -61,7 +67,9 @@
         mSensorPaint.setARGB(255, 255, 255, 255);
         mSensorPaint.setStyle(Paint.Style.FILL);
 
-        mIlluminationDotDrawable = canvas -> canvas.drawOval(mSensorRect, mSensorPaint);
+        mIlluminationDotDrawable = canvas -> {
+            canvas.drawOval(mSensorRect, mSensorPaint);
+        };
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
index 6ffecdb..cd849e6 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
@@ -32,7 +32,6 @@
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.FrameLayout;
 
@@ -51,12 +50,11 @@
 
     private static final int DEBUG_TEXT_SIZE_PX = 32;
 
-    @NonNull private final UdfpsSurfaceView mHbmSurfaceView;
-    @NonNull private final UdfpsAnimationView mAnimationView;
     @NonNull private final RectF mSensorRect;
     @NonNull private final Paint mDebugTextPaint;
 
-    @Nullable private UdfpsProgressBar mProgressBar;
+    @NonNull private UdfpsSurfaceView mHbmSurfaceView;
+    @Nullable private UdfpsAnimationView mAnimationView;
 
     // Used to obtain the sensor location.
     @NonNull private FingerprintSensorPropertiesInternal mSensorProps;
@@ -66,7 +64,6 @@
     private boolean mIlluminationRequested;
     private int mStatusBarState;
     private boolean mNotificationShadeExpanded;
-    @Nullable private UdfpsEnrollHelper mEnrollHelper;
 
     public UdfpsView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -84,19 +81,6 @@
             a.recycle();
         }
 
-        // Inflate UdfpsSurfaceView
-        final LayoutInflater inflater = LayoutInflater.from(context);
-        mHbmSurfaceView = (UdfpsSurfaceView) inflater.inflate(R.layout.udfps_surface_view,
-                null, false);
-        addView(mHbmSurfaceView);
-        mHbmSurfaceView.setVisibility(View.INVISIBLE);
-
-        // Inflate UdfpsAnimationView
-        mAnimationView = (UdfpsAnimationView) inflater.inflate(R.layout.udfps_animation_view,
-                null, false);
-        mAnimationView.setParent(this);
-        addView(mAnimationView);
-
         mSensorRect = new RectF();
 
         mDebugTextPaint = new Paint();
@@ -107,22 +91,22 @@
         mIlluminationRequested = false;
     }
 
+    @Override
+    protected void onFinishInflate() {
+        mHbmSurfaceView = findViewById(R.id.hbm_view);
+    }
+
     void setSensorProperties(@NonNull FingerprintSensorPropertiesInternal properties) {
         mSensorProps = properties;
     }
 
-    void setExtras(@Nullable UdfpsAnimation animation, @Nullable UdfpsEnrollHelper enrollHelper) {
-        mAnimationView.setAnimation(animation);
+    void setAnimationView(@NonNull UdfpsAnimationView animation) {
+        mAnimationView = animation;
+        animation.setParent(this);
 
-        mEnrollHelper = enrollHelper;
-
-        if (enrollHelper != null) {
-            mEnrollHelper.updateProgress(mProgressBar);
-            mProgressBar.setVisibility(enrollHelper.shouldShowProgressBar()
-                    ? View.VISIBLE : View.GONE);
-        } else {
-            mProgressBar.setVisibility(View.GONE);
-        }
+        // TODO: Consider using a ViewStub placeholder to maintain positioning and inflating it
+        //  after the animation type has been decided.
+        addView(animation, 0);
     }
 
     @Override
@@ -132,27 +116,24 @@
 
     @Override
     public void dozeTimeTick() {
+        if (mAnimationView == null) {
+            return;
+        }
         mAnimationView.dozeTimeTick();
     }
 
     @Override
-    public void onExpandedChanged(boolean isExpanded) {
-        mNotificationShadeExpanded = isExpanded;
-    }
-
-    @Override
     public void onStateChanged(int newState) {
         mStatusBarState = newState;
     }
 
     @Override
     public void onExpansionChanged(float expansion, boolean expanded) {
-        mAnimationView.onExpansionChanged(expansion, expanded);
-    }
+        mNotificationShadeExpanded = expanded;
 
-    @Override
-    protected void onFinishInflate() {
-        mProgressBar = findViewById(R.id.progress_bar);
+        if (mAnimationView != null) {
+            mAnimationView.onExpansionChanged(expansion, expanded);
+        }
     }
 
     @Override
@@ -192,10 +173,6 @@
         }
     }
 
-    RectF getSensorRect() {
-        return new RectF(mSensorRect);
-    }
-
     void setDebugMessage(String message) {
         mDebugMessage = message;
         postInvalidate();
@@ -237,7 +214,7 @@
     @Override
     public void startIllumination(@Nullable Runnable onIlluminatedRunnable) {
         mIlluminationRequested = true;
-        mAnimationView.setVisibility(View.INVISIBLE);
+        mAnimationView.onIlluminationStarting();
         mHbmSurfaceView.setVisibility(View.VISIBLE);
         mHbmSurfaceView.startIllumination(onIlluminatedRunnable);
     }
@@ -245,16 +222,8 @@
     @Override
     public void stopIllumination() {
         mIlluminationRequested = false;
-        mAnimationView.setVisibility(View.VISIBLE);
+        mAnimationView.onIlluminationStopped();
         mHbmSurfaceView.setVisibility(View.INVISIBLE);
         mHbmSurfaceView.stopIllumination();
     }
-
-    void onEnrollmentProgress(int remaining) {
-        mEnrollHelper.onEnrollmentProgress(remaining, mProgressBar);
-    }
-
-    void onEnrollmentHelp() {
-
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt
index cad166d..1ea1d97 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt
@@ -41,7 +41,7 @@
 
 object ControlsAnimations {
 
-    private const val ALPHA_EXIT_DURATION = 167L
+    private const val ALPHA_EXIT_DURATION = 183L
     private const val ALPHA_ENTER_DELAY = ALPHA_EXIT_DURATION
     private const val ALPHA_ENTER_DURATION = 350L - ALPHA_ENTER_DELAY
 
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
index 1c2f17c..2d647a9 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
@@ -313,6 +313,10 @@
             setOnClickListener {
                 val i = Intent().apply {
                     component = ComponentName(context, ControlsProviderSelectorActivity::class.java)
+                    putExtra(
+                        ControlsUiController.BACK_TO_GLOBAL_ACTIONS,
+                        backToGlobalActions
+                    )
                 }
                 if (doneButton.isEnabled) {
                     // The user has made changes
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
index 0814774..d5e41d0 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
@@ -32,6 +32,8 @@
 import com.android.systemui.R
 import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.controls.controller.ControlsController
+import com.android.systemui.controls.ui.ControlsDialog
+import com.android.systemui.controls.ui.ControlsUiController
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.globalactions.GlobalActionsComponent
@@ -49,13 +51,15 @@
     private val listingController: ControlsListingController,
     private val controlsController: ControlsController,
     private val globalActionsComponent: GlobalActionsComponent,
-    broadcastDispatcher: BroadcastDispatcher
+    private val broadcastDispatcher: BroadcastDispatcher,
+    private val uiController: ControlsUiController
 ) : LifecycleActivity() {
 
     companion object {
         private const val TAG = "ControlsProviderSelectorActivity"
     }
 
+    private var backToGlobalActions = true
     private lateinit var recyclerView: RecyclerView
     private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) {
         private val startingUser = listingController.currentUserId
@@ -101,10 +105,19 @@
             }
         }
         requireViewById<View>(R.id.done).visibility = View.GONE
+
+        backToGlobalActions = intent.getBooleanExtra(
+            ControlsUiController.BACK_TO_GLOBAL_ACTIONS,
+            true
+        )
     }
 
     override fun onBackPressed() {
-        globalActionsComponent.handleShowGlobalActionsMenu()
+        if (backToGlobalActions) {
+            globalActionsComponent.handleShowGlobalActionsMenu()
+        } else {
+            ControlsDialog(applicationContext, broadcastDispatcher).show(uiController)
+        }
         animateExitAndFinish()
     }
 
@@ -152,8 +165,13 @@
                             listingController.getAppLabel(it))
                     putExtra(Intent.EXTRA_COMPONENT_NAME, it)
                     putExtra(ControlsFavoritingActivity.EXTRA_FROM_PROVIDER_SELECTOR, true)
+                    putExtra(
+                        ControlsUiController.BACK_TO_GLOBAL_ACTIONS,
+                        backToGlobalActions
+                    )
                 }
                 startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle())
+                animateExitAndFinish()
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 726e2d0..a2f96bb 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -25,6 +25,7 @@
 import android.content.SharedPreferences;
 import android.content.om.OverlayManager;
 import android.hardware.display.AmbientDisplayConfiguration;
+import android.hardware.display.ColorDisplayManager;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
@@ -60,6 +61,7 @@
 import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.plugins.PluginInitializerImpl;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.qs.ReduceBrightColorsController;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.settings.UserTracker;
@@ -82,6 +84,7 @@
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.theme.ThemeOverlayApplier;
 import com.android.systemui.util.leak.LeakDetector;
+import com.android.systemui.util.settings.SecureSettings;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
 import com.android.wm.shell.pip.Pip;
 
@@ -266,6 +269,15 @@
     }
 
     /** */
+    @SysUISingleton
+    @Provides
+    public ReduceBrightColorsController provideReduceBrightColorsListener(
+            @Background Handler bgHandler, UserTracker userTracker,
+            ColorDisplayManager colorDisplayManager, SecureSettings secureSettings) {
+        return new ReduceBrightColorsController(userTracker, bgHandler,
+                colorDisplayManager, secureSettings);
+    }
+
     @Provides
     @SysUISingleton
     public ActivityManagerWrapper provideActivityManagerWrapper() {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index ffb8446..8f79de5 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -33,6 +33,7 @@
 import com.android.wm.shell.onehanded.OneHanded;
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.splitscreen.SplitScreen;
+import com.android.wm.shell.startingsurface.StartingSurface;
 import com.android.wm.shell.transition.RemoteTransitions;
 
 import java.util.Optional;
@@ -88,6 +89,9 @@
         @BindsInstance
         Builder setTransitions(RemoteTransitions t);
 
+        @BindsInstance
+        Builder setStartingSurface(Optional<StartingSurface> s);
+
         SysUIComponent build();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index 5d226d5..1ed8819 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -27,7 +27,6 @@
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.dagger.KeyguardModule;
 import com.android.systemui.media.systemsounds.HomeSoundEffectController;
-import com.android.systemui.people.widget.PeopleSpaceWidgetEnabler;
 import com.android.systemui.power.PowerUI;
 import com.android.systemui.privacy.television.TvOngoingPrivacyChip;
 import com.android.systemui.recents.Recents;
@@ -185,10 +184,4 @@
     @IntoMap
     @ClassKey(HomeSoundEffectController.class)
     public abstract SystemUI bindHomeSoundEffectController(HomeSoundEffectController sysui);
-
-    /** Inject into PeopleSpaceWidgetEnabler. */
-    @Binds
-    @IntoMap
-    @ClassKey(PeopleSpaceWidgetEnabler.class)
-    public abstract SystemUI bindPeopleSpaceWidgetEnabler(PeopleSpaceWidgetEnabler sysui);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index f3726a3..1b77d1c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -32,6 +32,7 @@
 import com.android.wm.shell.onehanded.OneHanded;
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.splitscreen.SplitScreen;
+import com.android.wm.shell.startingsurface.StartingSurface;
 import com.android.wm.shell.transition.RemoteTransitions;
 
 import java.util.Optional;
@@ -98,4 +99,7 @@
 
     @WMSingleton
     RemoteTransitions getTransitions();
+
+    @WMSingleton
+    Optional<StartingSurface> getStartingSurface();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
index d4678f3..127128d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
@@ -103,6 +103,11 @@
      */
     public void updateIndication(@IndicationType int type, KeyguardIndication newIndication,
             boolean showImmediately) {
+        if (type == INDICATION_TYPE_NOW_PLAYING
+                || type == INDICATION_TYPE_REVERSE_CHARGING) {
+            // temporarily don't show here, instead use AmbientContainer b/181049781
+            return;
+        }
         final boolean hasPreviousIndication = mIndicationMessages.get(type) != null;
         final boolean hasNewIndication = newIndication != null;
         if (!hasNewIndication) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 19e3278..35d5ca9 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -279,9 +279,11 @@
             return;
         }
 
+        // When in gestural and the IME is showing, don't use the nearest region since it will take
+        // gesture space away from the IME
         info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
         info.touchableRegion.set(getButtonLocations(false /* includeFloatingRotationButton */,
-                false /* inScreen */));
+                false /* inScreen */, false /* useNearestRegion */));
     };
 
     private final Consumer<Boolean> mRotationButtonListener = (visible) -> {
@@ -981,7 +983,8 @@
      */
     public void notifyActiveTouchRegions() {
         mOverviewProxyService.onActiveNavBarRegionChanges(
-                getButtonLocations(true /* includeFloatingRotationButton */, true /* inScreen */));
+                getButtonLocations(true /* includeFloatingRotationButton */, true /* inScreen */,
+                        true /* useNearestRegion */));
     }
 
     private void updateButtonTouchRegionCache() {
@@ -992,35 +995,49 @@
                 .findViewById(R.id.nav_buttons)).getFullTouchableChildRegions();
     }
 
+    /**
+     * @param includeFloatingRotationButton Whether to include the floating rotation button in the
+     *                                      region for all the buttons
+     * @param inScreenSpace Whether to return values in screen space or window space
+     * @param useNearestRegion Whether to use the nearest region instead of the actual button bounds
+     * @return
+     */
     private Region getButtonLocations(boolean includeFloatingRotationButton,
-            boolean inScreenSpace) {
+            boolean inScreenSpace, boolean useNearestRegion) {
+        if (useNearestRegion && !inScreenSpace) {
+            // We currently don't support getting the nearest region in anything but screen space
+            useNearestRegion = false;
+        }
         mTmpRegion.setEmpty();
         updateButtonTouchRegionCache();
-        updateButtonLocation(getBackButton(), inScreenSpace);
-        updateButtonLocation(getHomeButton(), inScreenSpace);
-        updateButtonLocation(getRecentsButton(), inScreenSpace);
-        updateButtonLocation(getImeSwitchButton(), inScreenSpace);
-        updateButtonLocation(getAccessibilityButton(), inScreenSpace);
+        updateButtonLocation(getBackButton(), inScreenSpace, useNearestRegion);
+        updateButtonLocation(getHomeButton(), inScreenSpace, useNearestRegion);
+        updateButtonLocation(getRecentsButton(), inScreenSpace, useNearestRegion);
+        updateButtonLocation(getImeSwitchButton(), inScreenSpace, useNearestRegion);
+        updateButtonLocation(getAccessibilityButton(), inScreenSpace, useNearestRegion);
         if (includeFloatingRotationButton && mFloatingRotationButton.isVisible()) {
+            // Note: this button is floating so the nearest region doesn't apply
             updateButtonLocation(mFloatingRotationButton.getCurrentView(), inScreenSpace);
         } else {
-            updateButtonLocation(getRotateSuggestionButton(), inScreenSpace);
+            updateButtonLocation(getRotateSuggestionButton(), inScreenSpace, useNearestRegion);
         }
         if (mNavBarOverlayController.isNavigationBarOverlayEnabled()
                 && mNavBarOverlayController.isVisible()) {
+            // Note: this button is floating so the nearest region doesn't apply
             updateButtonLocation(mNavBarOverlayController.getCurrentView(), inScreenSpace);
         }
         return mTmpRegion;
     }
 
-    private void updateButtonLocation(ButtonDispatcher button, boolean inScreenSpace) {
+    private void updateButtonLocation(ButtonDispatcher button, boolean inScreenSpace,
+            boolean useNearestRegion) {
         View view = button.getCurrentView();
         if (view == null || !button.isVisible()) {
             return;
         }
         // If the button is tappable from perspective of NearestTouchFrame, then we'll
         // include the regions where the tap is valid instead of just the button layout location
-        if (mButtonFullTouchableRegions.containsKey(view)) {
+        if (useNearestRegion && mButtonFullTouchableRegions.containsKey(view)) {
             mTmpRegion.op(mButtonFullTouchableRegions.get(view), Op.UNION);
             return;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java
index 65d4e23..422ffd5 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java
@@ -132,7 +132,7 @@
             Settings.Secure.putString(mCurrentUserContext.getContentResolver(),
                     Secure.NAVIGATION_MODE, String.valueOf(mode)));
         if (DEBUG) {
-            Log.e(TAG, "updateCurrentInteractionMode: mode=" + mode);
+            Log.d(TAG, "updateCurrentInteractionMode: mode=" + mode);
             dumpAssetPaths(mCurrentUserContext);
         }
 
@@ -200,7 +200,7 @@
         Log.d(TAG, "  assetPaths=");
         ApkAssets[] assets = context.getResources().getAssets().getApkAssets();
         for (ApkAssets a : assets) {
-            Log.d(TAG, "    " + a.getAssetPath());
+            Log.d(TAG, "    " + a.getDebugName());
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/NearestTouchFrame.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/NearestTouchFrame.java
index b1c85b5..8ff7b7a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/NearestTouchFrame.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/NearestTouchFrame.java
@@ -84,19 +84,14 @@
     }
 
     @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
         mClickableChildren.clear();
         mAttachedChildren.clear();
         mTouchableRegions.clear();
         addClickableChildren(this);
-        cacheClosestChildLocations();
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
         getLocationInWindow(mOffset);
+        cacheClosestChildLocations();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
index 2f9b17a..2ea8657 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
@@ -19,8 +19,6 @@
 import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID;
 import static android.appwidget.AppWidgetManager.INVALID_APPWIDGET_ID;
 
-import static com.android.systemui.people.PeopleSpaceUtils.getUserHandle;
-
 import android.app.Activity;
 import android.app.INotificationManager;
 import android.app.people.IPeopleManager;
@@ -155,7 +153,7 @@
                 if (DEBUG) Log.d(TAG, "Caching shortcut for PeopleTile: " + tile.getId());
                 mLauncherApps.cacheShortcuts(tile.getPackageName(),
                         Collections.singletonList(tile.getId()),
-                        getUserHandle(tile), LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS);
+                        tile.getUserHandle(), LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS);
             } catch (Exception e) {
                 Log.w(TAG, "Exception caching shortcut:" + e);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java
index 9ae7847..6f89332 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java
@@ -21,7 +21,6 @@
 import android.content.pm.LauncherApps;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
-import android.os.UserHandle;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -82,7 +81,7 @@
     public void setOnClickListener(LauncherApps launcherApps, PeopleSpaceTile tile) {
         mTileView.setOnClickListener(v ->
                 launcherApps.startShortcut(tile.getPackageName(), tile.getId(), null, null,
-                        UserHandle.getUserHandleForUid(tile.getUid())));
+                        tile.getUserHandle()));
     }
 
     /** Sets the click listener of the tile directly. */
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
index 5dda23e..41080af 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
@@ -55,7 +55,6 @@
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.os.ServiceManager;
-import android.os.UserHandle;
 import android.provider.ContactsContract;
 import android.provider.Settings;
 import android.service.notification.ConversationChannelWrapper;
@@ -160,7 +159,6 @@
         List<ConversationChannelWrapper> conversations =
                 notificationManager.getConversations(
                         false).getList();
-
         // Add priority conversations to tiles list.
         Stream<ShortcutInfo> priorityConversations = conversations.stream()
                 .filter(c -> c.getNotificationChannel() != null
@@ -252,7 +250,11 @@
             }
 
             // If tile is null, we need to retrieve from persisted storage.
-            if (DEBUG) Log.d(TAG, "Retrieving from storage after reboots");
+            if (DEBUG) {
+                Log.d(TAG,
+                        "Retrieving from storage after reboots: " + shortcutId + " user: " + userId
+                                + " pkg: " + pkg);
+            }
             LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
             ConversationChannel channel = peopleManager.getConversation(pkg, userId, shortcutId);
             if (channel == null) {
@@ -384,7 +386,7 @@
             PeopleSpaceTile tile, Map<String, NotificationEntry> visibleNotifications) {
         String shortcutId = tile.getId();
         String packageName = tile.getPackageName();
-        int userId = UserHandle.getUserHandleForUid(tile.getUid()).getIdentifier();
+        int userId = getUserId(tile);
         String key = getKey(shortcutId, packageName, userId);
         if (!visibleNotifications.containsKey(key)) {
             if (DEBUG) Log.d(TAG, "No existing notifications for key:" + key);
@@ -641,7 +643,8 @@
             activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_TILE_ID, tile.getId());
             activityIntent.putExtra(
                     PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME, tile.getPackageName());
-            activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_UID, tile.getUid());
+            activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_USER_HANDLE,
+                    tile.getUserHandle());
             views.setOnClickPendingIntent(R.id.item, PendingIntent.getActivity(
                     context,
                     appWidgetId,
@@ -788,7 +791,6 @@
             Log.i(TAG, "ConversationChannel is null");
             return null;
         }
-
         PeopleSpaceTile tile = new PeopleSpaceTile.Builder(channel, launcherApps).build();
         if (!PeopleSpaceUtils.shouldKeepConversation(tile)) {
             Log.i(TAG, "PeopleSpaceTile is not valid");
@@ -1069,11 +1071,6 @@
 
     /** Returns the userId associated with a {@link PeopleSpaceTile} */
     public static int getUserId(PeopleSpaceTile tile) {
-        return getUserHandle(tile).getIdentifier();
-    }
-
-    /** Returns the {@link UserHandle} associated with a {@link PeopleSpaceTile} */
-    public static UserHandle getUserHandle(PeopleSpaceTile tile) {
-        return UserHandle.getUserHandleForUid(tile.getUid());
+        return tile.getUserHandle().getIdentifier();
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java b/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java
index 358f311..13e30f9 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java
@@ -41,7 +41,8 @@
         Intent intent = getIntent();
         String tileId = intent.getStringExtra(PeopleSpaceWidgetProvider.EXTRA_TILE_ID);
         String packageName = intent.getStringExtra(PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME);
-        int uid = intent.getIntExtra(PeopleSpaceWidgetProvider.EXTRA_UID, 0);
+        UserHandle userHandle = intent.getParcelableExtra(
+                PeopleSpaceWidgetProvider.EXTRA_USER_HANDLE);
 
         if (tileId != null && !tileId.isEmpty()) {
             if (DEBUG) {
@@ -52,7 +53,7 @@
                 LauncherApps launcherApps =
                         getApplicationContext().getSystemService(LauncherApps.class);
                 launcherApps.startShortcut(
-                        packageName, tileId, null, null, UserHandle.getUserHandleForUid(uid));
+                        packageName, tileId, null, null, userHandle);
             } catch (Exception e) {
                 Log.e(TAG, "Exception starting shortcut:" + e);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetEnabler.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetEnabler.java
deleted file mode 100644
index 3df2644..0000000
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetEnabler.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.people.widget;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.util.Log;
-
-import com.android.systemui.SystemUI;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.people.PeopleSpaceActivity;
-import com.android.systemui.statusbar.FeatureFlags;
-
-import javax.inject.Inject;
-
-/**
- * Enables People Space widgets.
- */
-@SysUISingleton
-public class PeopleSpaceWidgetEnabler extends SystemUI {
-    private static final String TAG = "PeopleSpaceWdgtEnabler";
-    private Context mContext;
-    private FeatureFlags mFeatureFlags;
-
-    @Inject
-    public PeopleSpaceWidgetEnabler(Context context, FeatureFlags featureFlags) {
-        super(context);
-        mContext = context;
-        mFeatureFlags = featureFlags;
-    }
-
-    @Override
-    public void start() {
-        Log.d(TAG, "Starting service");
-        try {
-            boolean showPeopleSpace = mFeatureFlags.isPeopleTileEnabled();
-            mContext.getPackageManager().setComponentEnabledSetting(
-                    new ComponentName(mContext, PeopleSpaceWidgetProvider.class),
-                    showPeopleSpace
-                            ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
-                            : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
-                    PackageManager.DONT_KILL_APP);
-            mContext.getPackageManager().setComponentEnabledSetting(
-                    new ComponentName(mContext, PeopleSpaceActivity.class),
-                    showPeopleSpace
-                            ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
-                            : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
-                    PackageManager.DONT_KILL_APP);
-        } catch (Exception e) {
-            Log.w(TAG, "Error enabling People Space widget:", e);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java
index 3d1055f..90baf56 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java
@@ -48,7 +48,7 @@
 
     public static final String EXTRA_TILE_ID = "extra_tile_id";
     public static final String EXTRA_PACKAGE_NAME = "extra_package_name";
-    public static final String EXTRA_UID = "extra_uid";
+    public static final String EXTRA_USER_HANDLE = "extra_user_handle";
 
     public UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
 
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java
index 80794cb..0503522 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java
@@ -123,7 +123,8 @@
             fillInIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_TILE_ID, tile.getId());
             fillInIntent.putExtra(
                     PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME, tile.getPackageName());
-            fillInIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_UID, tile.getUid());
+            fillInIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_USER_HANDLE,
+                    tile.getUserHandle());
             personView.setOnClickFillInIntent(R.id.item, fillInIntent);
         } catch (Exception e) {
             Log.e(TAG, "Couldn't retrieve shortcut information", e);
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt
index 680a617..7679d48 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt
@@ -64,6 +64,7 @@
         super.onCreate(savedInstanceState)
         window?.apply {
             attributes.fitInsetsTypes = attributes.fitInsetsTypes or WindowInsets.Type.statusBars()
+            attributes.receiveInsetsIgnoringZOrder = true
             setLayout(context.resources.getDimensionPixelSize(R.dimen.qs_panel_width), WRAP_CONTENT)
             setGravity(Gravity.TOP or Gravity.CENTER_HORIZONTAL)
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index eaf2123..fcb56a4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -71,7 +71,6 @@
     private int mMinRows = 1;
     private int mMaxColumns = TileLayout.NO_MAX_COLUMNS;
 
-    private boolean mShowLabels = true;
     private final boolean mSideLabels;
 
     public PagedTileLayout(Context context, AttributeSet attrs) {
@@ -91,16 +90,6 @@
     }
     private int mLastMaxHeight = -1;
 
-    @Override
-    public void setShowLabels(boolean show) {
-        mShowLabels = show;
-        for (TileLayout p : mPages) {
-            p.setShowLabels(show);
-        }
-        mDistributeTiles = true;
-        requestLayout();
-    }
-
     public void saveInstanceState(Bundle outState) {
         outState.putInt(CURRENT_PAGE, getCurrentItem());
     }
@@ -239,7 +228,6 @@
                         : R.layout.qs_paged_page, this, false);
         page.setMinRows(mMinRows);
         page.setMaxColumns(mMaxColumns);
-        page.setShowLabels(mShowLabels);
         return page;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index c8edaec..fe76668 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -29,7 +29,6 @@
 import com.android.systemui.qs.TouchAnimator.Builder;
 import com.android.systemui.qs.TouchAnimator.Listener;
 import com.android.systemui.qs.dagger.QSScope;
-import com.android.systemui.qs.tileimpl.QSTileBaseView;
 import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
@@ -56,7 +55,8 @@
     private final ArrayList<View> mAllViews = new ArrayList<>();
     /**
      * List of {@link View}s representing Quick Settings that are being animated from the quick QS
-     * position to the normal QS panel.
+     * position to the normal QS panel. These views will only show once the animation is complete,
+     * to prevent overlapping of semi transparent views
      */
     private final ArrayList<View> mQuickQsViews = new ArrayList<>();
     private final QuickQSPanel mQuickQsPanel;
@@ -233,7 +233,6 @@
                 // Quick tiles.
                 QSTileView quickTileView = mQuickQSPanelController.getTileView(tile);
                 if (quickTileView == null) continue;
-                View qqsBgCircle = ((QSTileBaseView) quickTileView).getBgCircle();
 
                 getRelativePosition(loc1, quickTileView.getIcon().getIconView(), view);
                 getRelativePosition(loc2, tileIcon, view);
@@ -255,11 +254,6 @@
                     translationXBuilder.addFloat(tileView, "translationX", -xDiff, 0);
                     translationYBuilder.addFloat(tileView, "translationY", -yDiff, 0);
 
-                    if (mFeatureFlags.isQSLabelsEnabled()) {
-                        firstPageBuilder.addFloat(qqsBgCircle, "alpha", 1, 1, 0);
-                        mAllViews.add(qqsBgCircle);
-                    }
-
                 } else { // These tiles disappear when expanding
                     firstPageBuilder.addFloat(quickTileView, "alpha", 1, 0);
                     translationYBuilder.addFloat(quickTileView, "translationY", 0, yDiff);
@@ -271,7 +265,11 @@
                             translationX);
                 }
 
-                mQuickQsViews.add(tileView.getIconWithBackground());
+                if (mFeatureFlags.isQSLabelsEnabled()) {
+                    mQuickQsViews.add(tileView);
+                } else {
+                    mQuickQsViews.add(tileView.getIconWithBackground());
+                }
                 mAllViews.add(tileView.getIcon());
                 mAllViews.add(quickTileView);
             } else if (mFullRows && isIconInAnimatedRow(count)) {
@@ -362,7 +360,7 @@
         if(view == parent || view == null) return;
         // Ignore tile pages as they can have some offset we don't want to take into account in
         // RTL.
-        if (!(view instanceof PagedTileLayout.TilePage || view instanceof SideLabelTileLayout)) {
+        if (!isAPage(view)) {
             loc1[0] += view.getLeft();
             loc1[1] += view.getTop();
         }
@@ -374,6 +372,16 @@
         getRelativePositionInt(loc1, (View) view.getParent(), parent);
     }
 
+    // Returns true if the view is a possible page in PagedTileLayout
+    private boolean isAPage(View view) {
+        if (view instanceof PagedTileLayout.TilePage) {
+            return true;
+        } else if (view instanceof SideLabelTileLayout) {
+            return !(view instanceof QuickQSPanel.QQSSideLabelTileLayout);
+        }
+        return false;
+    }
+
     public void setPosition(float position) {
         if (mNeedsAnimatorUpdate) {
             updateAnimators();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
index 16e5196..2bea72c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.qs;
 
+import static com.android.systemui.qs.dagger.QSFlagsModule.PM_LITE_ENABLED;
+
 import android.content.ClipData;
 import android.content.ClipboardManager;
 import android.content.Intent;
@@ -41,6 +43,7 @@
 import com.android.systemui.util.ViewController;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 
 /**
  * Controller for {@link QSFooterView}.
@@ -63,6 +66,8 @@
     private final View mEdit;
     private final MultiUserSwitch mMultiUserSwitch;
     private final PageIndicator mPageIndicator;
+    private final View mPowerMenuLite;
+    private final boolean mShowPMLiteButton;
 
     private final UserInfoController.OnUserInfoChangedListener mOnUserInfoChangedListener =
             new UserInfoController.OnUserInfoChangedListener() {
@@ -123,7 +128,8 @@
             DeviceProvisionedController deviceProvisionedController, UserTracker userTracker,
             QSPanelController qsPanelController, QSDetailDisplayer qsDetailDisplayer,
             QuickQSPanelController quickQSPanelController,
-            TunerService tunerService, MetricsLogger metricsLogger) {
+            TunerService tunerService, MetricsLogger metricsLogger,
+            @Named(PM_LITE_ENABLED) boolean showPMLiteButton) {
         super(view);
         mUserManager = userManager;
         mUserInfoController = userInfoController;
@@ -141,10 +147,15 @@
         mEdit = mView.findViewById(android.R.id.edit);
         mMultiUserSwitch = mView.findViewById(R.id.multi_user_switch);
         mPageIndicator = mView.findViewById(R.id.footer_page_indicator);
+        mPowerMenuLite = mView.findViewById(R.id.pm_lite);
+        mShowPMLiteButton = showPMLiteButton;
     }
 
     @Override
     protected void onViewAttached() {
+        if (mShowPMLiteButton) {
+            mPowerMenuLite.setVisibility(View.VISIBLE);
+        }
         mView.addOnLayoutChangeListener(
                 (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
                         mView.updateAnimator(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 91ae571..7657dce 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -112,7 +112,7 @@
     private int mMediaTotalBottomMargin;
     private int mFooterMarginStartHorizontal;
     private Consumer<Boolean> mMediaVisibilityChangedListener;
-    private boolean mSideLabels;
+    protected boolean mSideLabels;
 
     public QSPanel(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -201,16 +201,20 @@
                 mFooterPageIndicator.setNumPages(((PagedTileLayout) mTileLayout).getNumPages());
             }
 
-            // Allow the UI to be as big as it want's to, we're in a scroll view
-            int newHeight = 10000;
-            int availableHeight = MeasureSpec.getSize(heightMeasureSpec);
-            int excessHeight = newHeight - availableHeight;
-            // Measure with EXACTLY. That way, The content will only use excess height and will
-            // be measured last, after other views and padding is accounted for. This only
-            // works because our Layouts in here remeasure themselves with the exact content
-            // height.
-            heightMeasureSpec = MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY);
-            ((PagedTileLayout) mTileLayout).setExcessHeight(excessHeight);
+            // In landscape, mTileLayout's parent is not the panel but a view that contains the
+            // tile layout and the media controls.
+            if (((View) mTileLayout).getParent() == this) {
+                // Allow the UI to be as big as it want's to, we're in a scroll view
+                int newHeight = 10000;
+                int availableHeight = MeasureSpec.getSize(heightMeasureSpec);
+                int excessHeight = newHeight - availableHeight;
+                // Measure with EXACTLY. That way, The content will only use excess height and will
+                // be measured last, after other views and padding is accounted for. This only
+                // works because our Layouts in here remeasure themselves with the exact content
+                // height.
+                heightMeasureSpec = MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY);
+                ((PagedTileLayout) mTileLayout).setExcessHeight(excessHeight);
+            }
         }
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 
@@ -758,7 +762,7 @@
                 // Let's use 3 columns to match the current layout
                 int columns;
                 if (mSideLabels) {
-                    columns = horizontal ? 1 : 2;
+                    columns = horizontal ? 2 : 4;
                 } else {
                     columns = horizontal ? 3 : TileLayout.NO_MAX_COLUMNS;
                 }
@@ -843,8 +847,6 @@
         default void setExpansion(float expansion) {}
 
         int getNumVisibleTiles();
-
-        default void setShowLabels(boolean show) {}
     }
 
     interface OnConfigurationChangedListener {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index fcb35e2..eda1abb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -18,7 +18,6 @@
 
 import static com.android.systemui.media.dagger.MediaModule.QS_PANEL;
 import static com.android.systemui.qs.QSPanel.QS_SHOW_BRIGHTNESS;
-import static com.android.systemui.qs.dagger.QSFlagsModule.QS_LABELS_FLAG;
 import static com.android.systemui.qs.dagger.QSFragmentModule.QS_USING_MEDIA_PLAYER;
 
 import android.annotation.NonNull;
@@ -66,7 +65,6 @@
 
     private BrightnessMirrorController mBrightnessMirrorController;
     private boolean mGridContentVisible = true;
-    private boolean mQsLabelsFlag;
 
     private final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener =
             new QSPanel.OnConfigurationChangedListener() {
@@ -93,7 +91,6 @@
             DumpManager dumpManager, MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
             QSLogger qsLogger, BrightnessController.Factory brightnessControllerFactory,
             BrightnessSlider.Factory brightnessSliderFactory,
-            @Named(QS_LABELS_FLAG) boolean qsLabelsFlag,
             FeatureFlags featureFlags) {
         super(view, qstileHost, qsCustomizerController, usingMediaPlayer, mediaHost,
                 metricsLogger, uiEventLogger, qsLogger, dumpManager, featureFlags);
@@ -108,9 +105,6 @@
         mView.setBrightnessView(mBrightnessSlider.getRootView());
 
         mBrightnessController = brightnessControllerFactory.create(mBrightnessSlider);
-
-        mQsLabelsFlag = qsLabelsFlag;
-        mSideLabels = qsLabelsFlag;
     }
 
     @Override
@@ -130,7 +124,6 @@
         updateMediaDisappearParameters();
 
         mTunerService.addTunable(mView, QS_SHOW_BRIGHTNESS);
-        mTunerService.addTunable(mTunable, QS_REMOVE_LABELS);
         mView.updateResources();
         if (mView.isListening()) {
             refreshAllTiles();
@@ -144,13 +137,6 @@
     }
 
     @Override
-    boolean switchTileLayout(boolean force) {
-        boolean result = super.switchTileLayout(force);
-        getTileLayout().setShowLabels(mShowLabels);
-        return result;
-    }
-
-    @Override
     protected QSTileRevealController createTileRevealController() {
         return mQsTileRevealControllerFactory.create(
                 this, (PagedTileLayout) mView.createRegularTileLayout());
@@ -158,7 +144,6 @@
 
     @Override
     protected void onViewDetached() {
-        mTunerService.removeTunable(mTunable);
         mTunerService.removeTunable(mView);
         mView.removeOnConfigurationChangedListener(mOnConfigurationChangedListener);
         if (mBrightnessMirrorController != null) {
@@ -324,22 +309,5 @@
     public boolean isExpanded() {
         return mView.isExpanded();
     }
-
-    private TunerService.Tunable mTunable = new TunerService.Tunable() {
-        @Override
-        public void onTuningChanged(String key, String newValue) {
-            if (QS_REMOVE_LABELS.equals(key)) {
-                if (!mQsLabelsFlag) return;
-                boolean newShowLabels = newValue == null || "0".equals(newValue);
-                if (mShowLabels == newShowLabels) return;
-                mShowLabels = newShowLabels;
-                for (TileRecord t : mRecords) {
-                    t.tileView.setShowLabels(mShowLabels);
-                }
-                getTileLayout().setShowLabels(mShowLabels);
-                mView.requestLayout();
-            }
-        }
-    };
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 9426e71..8ab1743 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -75,7 +75,7 @@
 
     private final QSHost.Callback mQSHostCallback = this::setTiles;
     protected boolean mShowLabels = true;
-    protected boolean mSideLabels;
+    protected boolean mQSLabelFlag;
 
     private final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener =
             new QSPanel.OnConfigurationChangedListener() {
@@ -118,11 +118,12 @@
         mQSLogger = qsLogger;
         mDumpManager = dumpManager;
         mFeatureFlags = featureFlags;
+        mQSLabelFlag = featureFlags.isQSLabelsEnabled();
     }
 
     @Override
     protected void onInit() {
-        mView.initialize(mSideLabels);
+        mView.initialize(mQSLabelFlag);
         mQSLogger.logAllTilesChangeListening(mView.isListening(), mView.getDumpableTag(), "");
     }
 
@@ -197,7 +198,6 @@
         final TileRecord r = new TileRecord();
         r.tile = tile;
         r.tileView = mHost.createTileView(tile, collapsedView);
-        r.tileView.setShowLabels(mShowLabels);
         mView.addTile(r);
         mRecords.add(r);
         mCachedSpecs = getTilesSpecs();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index a29ac3b..9b66b59 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -69,12 +69,22 @@
 
     @Override
     public TileLayout createRegularTileLayout() {
-        return new QuickQSPanel.HeaderTileLayout(mContext);
+        if (mSideLabels) {
+            return new QQSSideLabelTileLayout(mContext);
+        } else {
+            return new QuickQSPanel.HeaderTileLayout(mContext);
+        }
     }
 
     @Override
     protected QSTileLayout createHorizontalTileLayout() {
-        return new DoubleLineTileLayout(mContext);
+        if (mSideLabels) {
+            TileLayout t = createRegularTileLayout();
+            t.setMaxColumns(2);
+            return t;
+        } else {
+            return new DoubleLineTileLayout(mContext);
+        }
     }
 
     @Override
@@ -331,4 +341,38 @@
             }
         }
     }
+
+    static class QQSSideLabelTileLayout extends SideLabelTileLayout {
+        QQSSideLabelTileLayout(Context context) {
+            super(context, null);
+            setClipChildren(false);
+            setClipToPadding(false);
+            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
+                    LayoutParams.WRAP_CONTENT);
+            lp.gravity = Gravity.CENTER_HORIZONTAL;
+            setLayoutParams(lp);
+            setMaxColumns(4);
+        }
+
+        @Override
+        public boolean updateResources() {
+            boolean b = super.updateResources();
+            mMaxAllowedRows = 2;
+            return b;
+        }
+
+        @Override
+        protected void onConfigurationChanged(Configuration newConfig) {
+            super.onConfigurationChanged(newConfig);
+            updateResources();
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            // Make sure to always use the correct number of rows. As it's determined by the
+            // columns, just use as many as needed.
+            updateMaxRows(10000, mRecords.size());
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
index 383e932..671f8f7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -17,7 +17,6 @@
 package com.android.systemui.qs;
 
 import static com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL;
-import static com.android.systemui.qs.dagger.QSFlagsModule.QS_LABELS_FLAG;
 import static com.android.systemui.qs.dagger.QSFragmentModule.QS_USING_MEDIA_PLAYER;
 
 import com.android.internal.logging.MetricsLogger;
@@ -42,8 +41,6 @@
 @QSScope
 public class QuickQSPanelController extends QSPanelControllerBase<QuickQSPanel> {
 
-    private boolean mUseSideLabels;
-
     private final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener =
             newConfig -> {
                 int newMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
@@ -58,12 +55,10 @@
             @Named(QS_USING_MEDIA_PLAYER) boolean usingMediaPlayer,
             @Named(QUICK_QS_PANEL) MediaHost mediaHost,
             MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,
-            DumpManager dumpManager, @Named(QS_LABELS_FLAG) boolean qsLabelsFlag,
-            FeatureFlags featureFlags
+            DumpManager dumpManager, FeatureFlags featureFlags
     ) {
         super(view, qsTileHost, qsCustomizerController, usingMediaPlayer, mediaHost, metricsLogger,
                 uiEventLogger, qsLogger, dumpManager, featureFlags);
-        mUseSideLabels = qsLabelsFlag;
     }
 
     @Override
@@ -104,19 +99,7 @@
                 break;
             }
         }
-        if (mUseSideLabels) {
-            List<QSTile> newTiles = new ArrayList<>();
-            for (int i = 0; i < tiles.size(); i += 2) {
-                newTiles.add(tiles.get(i));
-            }
-            for (int i = 1; i < tiles.size(); i += 2) {
-                newTiles.add(tiles.get(i));
-            }
-            super.setTiles(newTiles, true);
-
-        } else {
-            super.setTiles(tiles, true);
-        }
+        super.setTiles(tiles, !mQSLabelFlag);
     }
 
     /** */
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java b/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java
new file mode 100644
index 0000000..42d603e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java
@@ -0,0 +1,140 @@
+/*
+ * 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.qs;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.hardware.display.ColorDisplayManager;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.provider.Settings;
+
+import androidx.annotation.NonNull;
+
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.policy.CallbackController;
+import com.android.systemui.util.settings.SecureSettings;
+
+import java.util.ArrayList;
+
+import javax.inject.Inject;
+
+/**
+ * @hide
+ */
+public class ReduceBrightColorsController implements
+        CallbackController<ReduceBrightColorsController.Listener> {
+    private final ColorDisplayManager mManager;
+    private final UserTracker mUserTracker;
+    private UserTracker.Callback mCurrentUserTrackerCallback;
+    private final Handler mHandler;
+    private final ContentObserver mContentObserver;
+    private final SecureSettings mSecureSettings;
+    private final ArrayList<ReduceBrightColorsController.Listener> mListeners = new ArrayList<>();
+
+    @Inject
+    public ReduceBrightColorsController(UserTracker userTracker,
+            @Background Handler handler,
+            ColorDisplayManager colorDisplayManager,
+            SecureSettings secureSettings) {
+        mManager = colorDisplayManager;
+        mUserTracker = userTracker;
+        mHandler = handler;
+        mSecureSettings = secureSettings;
+        mContentObserver = new ContentObserver(mHandler) {
+            @Override
+            public void onChange(boolean selfChange, Uri uri) {
+                super.onChange(selfChange, uri);
+                final String setting = uri == null ? null : uri.getLastPathSegment();
+                synchronized (mListeners) {
+                    if (setting != null && mListeners.size() != 0) {
+                        if (setting.equals(Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED)) {
+                            for (Listener listener : mListeners) {
+                                listener.onActivated(mManager.isReduceBrightColorsActivated());
+                            }
+                        }
+                    }
+                }
+            }
+        };
+
+        mCurrentUserTrackerCallback = new UserTracker.Callback() {
+            @Override
+            public void onUserChanged(int newUser, Context userContext) {
+                synchronized (mListeners) {
+                    if (mListeners.size() > 0) {
+                        mSecureSettings.unregisterContentObserver(mContentObserver);
+                        mSecureSettings.registerContentObserverForUser(
+                                Settings.Secure.getUriFor(
+                                        Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED),
+                                false, mContentObserver, newUser);
+                    }
+                }
+            }
+        };
+        mUserTracker.addCallback(mCurrentUserTrackerCallback, new HandlerExecutor(handler));
+    }
+
+    @Override
+    public void addCallback(@NonNull Listener listener) {
+        synchronized (mListeners) {
+            if (!mListeners.contains(listener)) {
+                mListeners.add(listener);
+                if (mListeners.size() == 1) {
+                    mSecureSettings.registerContentObserverForUser(
+                            Settings.Secure.getUriFor(
+                                    Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED),
+                            false, mContentObserver, mUserTracker.getUserId());
+                }
+            }
+        }
+    }
+
+    @Override
+    public void removeCallback(@androidx.annotation.NonNull Listener listener) {
+        synchronized (mListeners) {
+            if (mListeners.remove(listener) && mListeners.size() == 0) {
+                mSecureSettings.unregisterContentObserver(mContentObserver);
+            }
+        }
+    }
+
+    /** Returns {@code true} if Reduce Bright Colors is activated */
+    public boolean isReduceBrightColorsActivated() {
+        return mManager.isReduceBrightColorsActivated();
+    }
+
+    /** Sets the activation state of Reduce Bright Colors */
+    public void setReduceBrightColorsActivated(boolean activated) {
+        mManager.setReduceBrightColorsActivated(activated);
+    }
+
+    /**
+     * Listener invoked whenever the Reduce Bright Colors settings are changed.
+     */
+    public interface Listener {
+        /**
+         * Listener invoked when the activated state changes.
+         *
+         * @param activated {@code true} if Reduce Bright Colors is activated.
+         */
+        default void onActivated(boolean activated) {
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
index 74a7ac1..52f111e7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
@@ -18,22 +18,18 @@
 
 import android.content.Context
 import android.util.AttributeSet
-import com.android.systemui.R
 
-open class SideLabelTileLayout(context: Context, attrs: AttributeSet) : TileLayout(context, attrs) {
+open class SideLabelTileLayout(
+    context: Context,
+    attrs: AttributeSet?
+) : TileLayout(context, attrs) {
 
     override fun updateResources(): Boolean {
         return super.updateResources().also {
-            mResourceColumns = 2
             mMaxAllowedRows = 4
-            mCellMarginHorizontal = (mCellMarginHorizontal * 1.2).toInt()
-            mCellMarginVertical = mCellMarginHorizontal
-            mMaxCellHeight = context.resources.getDimensionPixelSize(R.dimen.qs_quick_tile_size)
         }
     }
 
-    override fun setShowLabels(show: Boolean) { }
-
     override fun isFull(): Boolean {
         return mRecords.size >= maxTiles()
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index d559e07..c1ce4a5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -36,7 +36,6 @@
     private int mCellMarginTop;
     protected boolean mListening;
     protected int mMaxAllowedRows = 3;
-    private boolean mShowLabels = true;
 
     // Prototyping with less rows
     private final boolean mLessRows;
@@ -57,12 +56,6 @@
     }
 
     @Override
-    public void setShowLabels(boolean show) {
-        mShowLabels = show;
-        updateResources();
-    }
-
-    @Override
     public int getOffsetTop(TileRecord tile) {
         return getTop();
     }
@@ -124,15 +117,13 @@
     public boolean updateResources() {
         final Resources res = mContext.getResources();
         mResourceColumns = Math.max(1, res.getInteger(R.integer.quick_settings_num_columns));
+        updateColumns();
         mMaxCellHeight = mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_height);
         mCellMarginHorizontal = res.getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal);
         mCellMarginVertical= res.getDimensionPixelSize(R.dimen.qs_tile_margin_vertical);
-        if (!mShowLabels && mCellMarginVertical == 0) {
-            mCellMarginVertical = mCellMarginHorizontal;
-        }
         mCellMarginTop = res.getDimensionPixelSize(R.dimen.qs_tile_margin_top);
         mMaxAllowedRows = Math.max(1, getResources().getInteger(R.integer.quick_settings_max_rows));
-        if (mLessRows && mShowLabels) mMaxAllowedRows = Math.max(mMinRows, mMaxAllowedRows - 1);
+        if (mLessRows) mMaxAllowedRows = Math.max(mMinRows, mMaxAllowedRows - 1);
         if (updateColumns()) {
             requestLayout();
             return true;
@@ -193,9 +184,8 @@
                 + mCellMarginVertical;
         final int previousRows = mRows;
         mRows = availableHeight / (getCellHeight() + mCellMarginVertical);
-        final int minRows = mShowLabels ? mMinRows : mMinRows + 1;
-        if (mRows < minRows) {
-            mRows = minRows;
+        if (mRows < mMinRows) {
+            mRows = mMinRows;
         } else if (mRows >= mMaxAllowedRows) {
             mRows = mMaxAllowedRows;
         }
@@ -215,7 +205,7 @@
     }
 
     protected int getCellHeight() {
-        return mShowLabels ? mMaxCellHeight : mMaxCellHeight / 2;
+        return mMaxCellHeight;
     }
 
     protected void layoutTileRecords(int numRecords) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
index a567f51..0dc0b30 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
@@ -42,6 +42,7 @@
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
 
 import java.util.function.Consumer;
 
@@ -74,30 +75,25 @@
     private final NetworkController.SignalCallback mSignalCallback =
             new NetworkController.SignalCallback() {
                 @Override
-                public void setMobileDataIndicators(NetworkController.IconState statusIcon,
-                        NetworkController.IconState qsIcon, int statusType, int qsType,
-                        boolean activityIn, boolean activityOut,
-                        CharSequence typeContentDescription,
-                        CharSequence typeContentDescriptionHtml, CharSequence description,
-                        boolean isWide, int subId, boolean roaming, boolean showTriangle) {
+                public void setMobileDataIndicators(MobileDataIndicators indicators) {
                     if (mProviderModel) {
                         return;
                     }
-                    int slotIndex = getSlotIndex(subId);
+                    int slotIndex = getSlotIndex(indicators.subId);
                     if (slotIndex >= SIM_SLOTS) {
                         Log.w(TAG, "setMobileDataIndicators - slot: " + slotIndex);
                         return;
                     }
                     if (slotIndex == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
-                        Log.e(TAG, "Invalid SIM slot index for subscription: " + subId);
+                        Log.e(TAG, "Invalid SIM slot index for subscription: " + indicators.subId);
                         return;
                     }
                     mInfos[slotIndex] = new CellSignalState(
-                            statusIcon.visible,
-                            statusIcon.icon,
-                            statusIcon.contentDescription,
-                            typeContentDescription.toString(),
-                            roaming
+                            indicators.statusIcon.visible,
+                            indicators.statusIcon.icon,
+                            indicators.statusIcon.contentDescription,
+                            indicators.typeContentDescription.toString(),
+                            indicators.roaming
                     );
                     mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget();
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
index 47cb45b..ce8f6c1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
@@ -16,19 +16,19 @@
 
 import android.content.Context;
 import android.view.View;
-import android.widget.TextView;
 
 import com.android.systemui.plugins.qs.QSIconView;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.qs.tileimpl.QSTileView;
 
-public class CustomizeTileView extends QSTileView {
+public class CustomizeTileView extends QSTileView implements TileAdapter.CustomizeView {
     private boolean mShowAppLabel;
 
     public CustomizeTileView(Context context, QSIconView icon) {
         super(context, icon);
     }
 
+    @Override
     public void setShowAppLabel(boolean showAppLabel) {
         mShowAppLabel = showAppLabel;
         mSecondLine.setVisibility(showAppLabel ? View.VISIBLE : View.GONE);
@@ -41,10 +41,6 @@
         mSecondLine.setVisibility(mShowAppLabel ? View.VISIBLE : View.GONE);
     }
 
-    public TextView getAppLabel() {
-        return mSecondLine;
-    }
-
     @Override
     protected boolean animationsEnabled() {
         return false;
@@ -54,4 +50,9 @@
     public boolean isLongClickable() {
         return false;
     }
+
+    @Override
+    public void changeState(QSTile.State state) {
+        handleStateChanged(state);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileViewHorizontal.kt b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileViewHorizontal.kt
new file mode 100644
index 0000000..4ffcd8c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileViewHorizontal.kt
@@ -0,0 +1,50 @@
+package com.android.systemui.qs.customize
+
+import android.content.Context
+import android.graphics.drawable.Drawable
+import android.view.View
+import com.android.systemui.plugins.qs.QSIconView
+import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.qs.tileimpl.QSTileViewHorizontal
+
+/**
+ * Class for displaying tiles in [QSCustomizer] with the new design (labels on the side).
+ *
+ * This is a class parallel to [CustomizeTileView], but inheriting from [QSTileViewHorizontal].
+ */
+class CustomizeTileViewHorizontal(
+    context: Context,
+    icon: QSIconView
+) : QSTileViewHorizontal(context, icon),
+    TileAdapter.CustomizeView {
+
+    private var showAppLabel = false
+
+    override fun setShowAppLabel(showAppLabel: Boolean) {
+        this.showAppLabel = showAppLabel
+        mSecondLine.visibility = if (showAppLabel) View.VISIBLE else View.GONE
+        mLabel.isSingleLine = showAppLabel
+    }
+
+    override fun handleStateChanged(state: QSTile.State) {
+        super.handleStateChanged(state)
+        mSecondLine.visibility = if (showAppLabel) View.VISIBLE else View.GONE
+    }
+
+    override fun animationsEnabled(): Boolean {
+        return false
+    }
+
+    override fun isLongClickable(): Boolean {
+        return false
+    }
+
+    override fun changeState(state: QSTile.State) {
+        handleStateChanged(state)
+    }
+
+    override fun newTileBackground(): Drawable? {
+        super.newTileBackground()
+        return paintDrawable
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 9fe949b..dce081f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -25,7 +25,6 @@
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.Menu;
-import android.view.MenuItem;
 import android.view.View;
 import android.widget.LinearLayout;
 import android.widget.Toolbar;
@@ -48,7 +47,6 @@
 public class QSCustomizer extends LinearLayout {
 
     static final int MENU_RESET = Menu.FIRST;
-    static final int MENU_REMOVE_LABELS = Menu.FIRST + 1;
     static final String EXTRA_QS_CUSTOMIZING = "qs_customizing";
 
     private final QSDetailClipper mClipper;
@@ -77,10 +75,6 @@
 
         toolbar.getMenu().add(Menu.NONE, MENU_RESET, 0,
                 mContext.getString(com.android.internal.R.string.reset));
-        // Prototype menu item
-        toolbar.getMenu()
-                .add(Menu.NONE, MENU_REMOVE_LABELS, Menu.NONE, R.string.qs_remove_labels)
-                .setCheckable(true);
         toolbar.setTitle(R.string.qs_edit);
         mRecyclerView = findViewById(android.R.id.list);
         mTransparentView = findViewById(R.id.customizer_transparent_view);
@@ -89,11 +83,6 @@
         mRecyclerView.setItemAnimator(animator);
     }
 
-    MenuItem getRemoveItem() {
-        return ((Toolbar) findViewById(com.android.internal.R.id.action_bar))
-                .getMenu().findItem(MENU_REMOVE_LABELS);
-    }
-
     void updateResources() {
         LayoutParams lp = (LayoutParams) mTransparentView.getLayoutParams();
         lp.height = mContext.getResources().getDimensionPixelSize(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
index d4bab21..f56a2bb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
@@ -17,9 +17,7 @@
 package com.android.systemui.qs.customize;
 
 import static com.android.systemui.qs.customize.QSCustomizer.EXTRA_QS_CUSTOMIZING;
-import static com.android.systemui.qs.customize.QSCustomizer.MENU_REMOVE_LABELS;
 import static com.android.systemui.qs.customize.QSCustomizer.MENU_RESET;
-import static com.android.systemui.qs.dagger.QSFlagsModule.QS_LABELS_FLAG;
 
 import android.content.res.Configuration;
 import android.os.Bundle;
@@ -38,7 +36,6 @@
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.qs.QSEditEvent;
 import com.android.systemui.qs.QSFragment;
-import com.android.systemui.qs.QSPanelController;
 import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.qs.dagger.QSScope;
 import com.android.systemui.statusbar.phone.LightBarController;
@@ -46,14 +43,12 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.tuner.TunerService;
 import com.android.systemui.util.ViewController;
 
 import java.util.ArrayList;
 import java.util.List;
 
 import javax.inject.Inject;
-import javax.inject.Named;
 
 /** {@link ViewController} for {@link QSCustomizer}. */
 @QSScope
@@ -67,8 +62,6 @@
     private final ConfigurationController mConfigurationController;
     private final UiEventLogger mUiEventLogger;
     private final Toolbar mToolbar;
-    private final TunerService mTunerService;
-    private final boolean mQsLabelsFlag;
 
     private final OnMenuItemClickListener mOnMenuItemClickListener = new OnMenuItemClickListener() {
         @Override
@@ -76,11 +69,6 @@
             if (item.getItemId() == MENU_RESET) {
                 mUiEventLogger.log(QSEditEvent.QS_EDIT_RESET);
                 reset();
-            } else if (item.getItemId() == MENU_REMOVE_LABELS) {
-                item.setChecked(!item.isChecked());
-                mTunerService.setValue(
-                        QSPanelController.QS_REMOVE_LABELS, item.isChecked() ? "1" : "0");
-                return false;
             }
             return false;
         }
@@ -111,20 +99,11 @@
         }
     };
 
-    private final TunerService.Tunable mTunable = new TunerService.Tunable() {
-        @Override
-        public void onTuningChanged(String key, String newValue) {
-            mToolbar.getMenu().findItem(MENU_REMOVE_LABELS)
-                    .setChecked(newValue != null && !("0".equals(newValue)));
-        }
-    };
-
     @Inject
     protected QSCustomizerController(QSCustomizer view, TileQueryHelper tileQueryHelper,
             QSTileHost qsTileHost, TileAdapter tileAdapter, ScreenLifecycle screenLifecycle,
             KeyguardStateController keyguardStateController, LightBarController lightBarController,
-            ConfigurationController configurationController, UiEventLogger uiEventLogger,
-            TunerService tunerService, @Named(QS_LABELS_FLAG) boolean qsLabelsFlag) {
+            ConfigurationController configurationController, UiEventLogger uiEventLogger) {
         super(view);
         mTileQueryHelper = tileQueryHelper;
         mQsTileHost = qsTileHost;
@@ -136,21 +115,12 @@
         mUiEventLogger = uiEventLogger;
 
         mToolbar = mView.findViewById(com.android.internal.R.id.action_bar);
-        mQsLabelsFlag = qsLabelsFlag;
-
-        mTunerService = tunerService;
     }
 
-    @Override
-    protected void onInit() {
-        super.onInit();
-        mView.getRemoveItem().setVisible(mQsLabelsFlag);
-    }
 
     @Override
     protected void onViewAttached() {
         mView.updateNavBackDrop(getResources().getConfiguration(), mLightBarController);
-        mTunerService.addTunable(mTunable, QSPanelController.QS_REMOVE_LABELS);
 
         mConfigurationController.addCallback(mConfigurationListener);
 
@@ -181,7 +151,6 @@
 
     @Override
     protected void onViewDetached() {
-        mTunerService.removeTunable(mTunable);
         mTileQueryHelper.setListener(null);
         mToolbar.setOnMenuItemClickListener(null);
         mConfigurationController.removeCallback(mConfigurationListener);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 048fdc3..0adc844 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -14,6 +14,8 @@
 
 package com.android.systemui.qs.customize;
 
+import static com.android.systemui.qs.dagger.QSFlagsModule.QS_LABELS_FLAG;
+
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
@@ -30,6 +32,7 @@
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.core.view.AccessibilityDelegateCompat;
 import androidx.core.view.ViewCompat;
 import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup;
@@ -41,6 +44,7 @@
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.R;
+import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.qs.QSEditEvent;
 import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.qs.customize.TileAdapter.Holder;
@@ -49,11 +53,13 @@
 import com.android.systemui.qs.dagger.QSScope;
 import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.qs.tileimpl.QSIconViewImpl;
+import com.android.systemui.qs.tileimpl.QSTileView;
 
 import java.util.ArrayList;
 import java.util.List;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 
 /** */
 @QSScope
@@ -75,6 +81,8 @@
     private static final int ACTION_ADD = 1;
     private static final int ACTION_MOVE = 2;
 
+    private static final int NUM_COLUMNS_ID = R.integer.quick_settings_num_columns;
+
     private final Context mContext;
 
     private final Handler mHandler = new Handler();
@@ -87,6 +95,7 @@
     private int mEditIndex;
     private int mTileDividerIndex;
     private int mFocusIndex;
+
     private boolean mNeedsFocus;
     private List<String> mCurrentSpecs;
     private List<TileInfo> mOtherTiles;
@@ -99,9 +108,11 @@
     private final AccessibilityDelegateCompat mAccessibilityDelegate;
     private RecyclerView mRecyclerView;
     private int mNumColumns;
+    private final boolean mUseHorizontalTiles;
 
     @Inject
-    public TileAdapter(Context context, QSTileHost qsHost, UiEventLogger uiEventLogger) {
+    public TileAdapter(Context context, QSTileHost qsHost, UiEventLogger uiEventLogger,
+            @Named(QS_LABELS_FLAG) boolean useHorizontalTiles) {
         mContext = context;
         mHost = qsHost;
         mUiEventLogger = uiEventLogger;
@@ -109,8 +120,9 @@
         mDecoration = new TileItemDecoration(context);
         mMarginDecoration = new MarginTileDecoration();
         mMinNumTiles = context.getResources().getInteger(R.integer.quick_settings_min_num_tiles);
-        mNumColumns = context.getResources().getInteger(R.integer.quick_settings_num_columns);
+        mNumColumns = context.getResources().getInteger(NUM_COLUMNS_ID);
         mAccessibilityDelegate = new TileAdapterDelegate();
+        mUseHorizontalTiles = useHorizontalTiles;
     }
 
     @Override
@@ -129,7 +141,7 @@
      * @return {@code true} if the number of columns changed, {@code false} otherwise
      */
     public boolean updateNumColumns() {
-        int numColumns = mContext.getResources().getInteger(R.integer.quick_settings_num_columns);
+        int numColumns = mContext.getResources().getInteger(NUM_COLUMNS_ID);
         if (numColumns != mNumColumns) {
             mNumColumns = numColumns;
             return true;
@@ -268,7 +280,10 @@
         }
         FrameLayout frame = (FrameLayout) inflater.inflate(R.layout.qs_customize_tile_frame, parent,
                 false);
-        frame.addView(new CustomizeTileView(context, new QSIconViewImpl(context)));
+        View view = mUseHorizontalTiles
+                ? new CustomizeTileViewHorizontal(context, new QSIconViewImpl(context))
+                : new CustomizeTileView(context, new QSIconViewImpl(context));
+        frame.addView(view);
         return new Holder(frame);
     }
 
@@ -351,8 +366,9 @@
         }
         info.state.expandedAccessibilityClassName = "";
 
-        holder.mTileView.handleStateChanged(info.state);
-        holder.mTileView.setShowAppLabel(position > mEditIndex && !info.isSystem);
+        // The holder has a tileView, therefore this call is not null
+        holder.getTileAsCustomizeView().changeState(info.state);
+        holder.getTileAsCustomizeView().setShowAppLabel(position > mEditIndex && !info.isSystem);
         holder.mTileView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
         holder.mTileView.setClickable(true);
         holder.mTileView.setOnClickListener(null);
@@ -531,25 +547,34 @@
     }
 
     public class Holder extends ViewHolder {
-        private CustomizeTileView mTileView;
+        private QSTileView mTileView;
 
         public Holder(View itemView) {
             super(itemView);
             if (itemView instanceof FrameLayout) {
-                mTileView = (CustomizeTileView) ((FrameLayout) itemView).getChildAt(0);
-                mTileView.setBackground(null);
+                mTileView = (QSTileView) ((FrameLayout) itemView).getChildAt(0);
+                if (mTileView instanceof CustomizeTileView) {
+                    mTileView.setBackground(null);
+                }
                 mTileView.getIcon().disableAnimation();
                 mTileView.setTag(this);
                 ViewCompat.setAccessibilityDelegate(mTileView, mAccessibilityDelegate);
             }
         }
 
+        @Nullable
+        public CustomizeView getTileAsCustomizeView() {
+            return (CustomizeView) mTileView;
+        }
+
         public void clearDrag() {
             itemView.clearAnimation();
-            mTileView.findViewById(R.id.tile_label).clearAnimation();
-            mTileView.findViewById(R.id.tile_label).setAlpha(1);
-            mTileView.getAppLabel().clearAnimation();
-            mTileView.getAppLabel().setAlpha(.6f);
+            if (mTileView instanceof CustomizeTileView) {
+                mTileView.findViewById(R.id.tile_label).clearAnimation();
+                mTileView.findViewById(R.id.tile_label).setAlpha(1);
+                mTileView.getAppLabel().clearAnimation();
+                mTileView.getAppLabel().setAlpha(.6f);
+            }
         }
 
         public void startDrag() {
@@ -557,12 +582,14 @@
                     .setDuration(DRAG_LENGTH)
                     .scaleX(DRAG_SCALE)
                     .scaleY(DRAG_SCALE);
-            mTileView.findViewById(R.id.tile_label).animate()
-                    .setDuration(DRAG_LENGTH)
-                    .alpha(0);
-            mTileView.getAppLabel().animate()
-                    .setDuration(DRAG_LENGTH)
-                    .alpha(0);
+            if (mTileView instanceof CustomizeTileView) {
+                mTileView.findViewById(R.id.tile_label).animate()
+                        .setDuration(DRAG_LENGTH)
+                        .alpha(0);
+                mTileView.getAppLabel().animate()
+                        .setDuration(DRAG_LENGTH)
+                        .alpha(0);
+            }
         }
 
         public void stopDrag() {
@@ -570,12 +597,14 @@
                     .setDuration(DRAG_LENGTH)
                     .scaleX(1)
                     .scaleY(1);
-            mTileView.findViewById(R.id.tile_label).animate()
-                    .setDuration(DRAG_LENGTH)
-                    .alpha(1);
-            mTileView.getAppLabel().animate()
-                    .setDuration(DRAG_LENGTH)
-                    .alpha(.6f);
+            if (mTileView instanceof CustomizeTileView) {
+                mTileView.findViewById(R.id.tile_label).animate()
+                        .setDuration(DRAG_LENGTH)
+                        .alpha(1);
+                mTileView.getAppLabel().animate()
+                        .setDuration(DRAG_LENGTH)
+                        .alpha(.6f);
+            }
         }
 
         boolean canRemove() {
@@ -719,7 +748,7 @@
                 int position = mCurrentDrag.getAdapterPosition();
                 if (position == RecyclerView.NO_POSITION) return;
                 TileInfo info = mTiles.get(position);
-                mCurrentDrag.mTileView.setShowAppLabel(
+                ((CustomizeView) mCurrentDrag.mTileView).setShowAppLabel(
                         position > mEditIndex && !info.isSystem);
                 mCurrentDrag.stopDrag();
                 mCurrentDrag = null;
@@ -779,4 +808,9 @@
         public void onSwiped(ViewHolder viewHolder, int direction) {
         }
     };
+
+    interface CustomizeView {
+        void setShowAppLabel(boolean showAppLabel);
+        void changeState(@NonNull QSTile.State state);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
index 35a8257..10192bc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
@@ -21,6 +21,7 @@
 
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.util.settings.GlobalSettings;
 
 import javax.inject.Named;
 
@@ -31,6 +32,8 @@
 public interface QSFlagsModule {
     String QS_LABELS_FLAG = "qs_labels_flag";
     String RBC_AVAILABLE = "rbc_available";
+    String PM_LITE_ENABLED = "pm_lite";
+    String PM_LITE_SETTING = "sysui_pm_lite";
 
     @Provides
     @SysUISingleton
@@ -46,4 +49,11 @@
     static boolean isReduceBrightColorsAvailable(Context context) {
         return ColorDisplayManager.isReduceBrightColorsAvailable(context);
     }
+
+    @Provides
+    @SysUISingleton
+    @Named(PM_LITE_ENABLED)
+    static boolean isPMLiteEnabled(FeatureFlags featureFlags, GlobalSettings globalSettings) {
+        return featureFlags.isPMLiteEnabled() && globalSettings.getInt(PM_LITE_SETTING, 0) != 0;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
index 33713f3..d41bd7a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.qs.dagger;
 
+import static com.android.systemui.qs.dagger.QSFlagsModule.RBC_AVAILABLE;
+
 import android.content.Context;
 import android.hardware.display.NightDisplayListener;
 import android.os.Handler;
@@ -25,6 +27,7 @@
 import com.android.systemui.qs.AutoAddTracker;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.ReduceBrightColorsController;
 import com.android.systemui.statusbar.phone.AutoTileManager;
 import com.android.systemui.statusbar.phone.ManagedProfileController;
 import com.android.systemui.statusbar.policy.CastController;
@@ -32,6 +35,8 @@
 import com.android.systemui.statusbar.policy.HotspotController;
 import com.android.systemui.util.settings.SecureSettings;
 
+import javax.inject.Named;
+
 import dagger.Binds;
 import dagger.Module;
 import dagger.Provides;
@@ -54,7 +59,9 @@
             DataSaverController dataSaverController,
             ManagedProfileController managedProfileController,
             NightDisplayListener nightDisplayListener,
-            CastController castController) {
+            CastController castController,
+            ReduceBrightColorsController reduceBrightColorsController,
+            @Named(RBC_AVAILABLE) boolean isReduceBrightColorsAvailable) {
         AutoTileManager manager = new AutoTileManager(
                 context,
                 autoAddTrackerBuilder,
@@ -65,7 +72,9 @@
                 dataSaverController,
                 managedProfileController,
                 nightDisplayListener,
-                castController
+                castController,
+                reduceBrightColorsController,
+                isReduceBrightColorsAvailable
         );
         manager.init();
         return manager;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
index a699e2e..b59326a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
@@ -105,24 +105,27 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        mLabel.setSingleLine(false);
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 
-        // Remeasure view if the primary label requires more then 2 lines or the secondary label
-        // text will be cut off.
-        if (mLabel.getLineCount() > mMaxLabelLines || !TextUtils.isEmpty(mSecondLine.getText())
-                        && mSecondLine.getLineHeight() > mSecondLine.getHeight()) {
-            if (!mLabel.isSingleLine()) {
-                mLabel.setSingleLine();
-                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-            }
-        } else {
-            if (mLabel.isSingleLine()) {
-                mLabel.setSingleLine(false);
-                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-            }
+        // Remeasure view if the primary label requires more than mMaxLabelLines lines or the
+        // secondary label text will be cut off.
+        if (shouldLabelBeSingleLine()) {
+            mLabel.setSingleLine();
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
         }
     }
 
+    private boolean shouldLabelBeSingleLine() {
+        if (mLabel.getLineCount() > mMaxLabelLines) {
+            return true;
+        } else if (!TextUtils.isEmpty(mSecondLine.getText())
+                && mLabel.getLineCount() > mMaxLabelLines - 1) {
+            return true;
+        }
+        return false;
+    }
+
     @Override
     protected void handleStateChanged(QSTile.State state) {
         super.handleStateChanged(state);
@@ -172,8 +175,7 @@
         mLabelContainer.setLongClickable(false);
     }
 
-    @Override
-    public void setShowLabels(boolean show) {
-        mHandler.post(() -> mLabelContainer.setVisibility(show ? VISIBLE : GONE));
+    public TextView getAppLabel() {
+        return mSecondLine;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
index dc81b702..231037f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.tileimpl
 
+import android.animation.ValueAnimator
 import android.content.Context
 import android.content.res.ColorStateList
 import android.graphics.Color
@@ -24,20 +25,24 @@
 import android.graphics.drawable.RippleDrawable
 import android.service.quicksettings.Tile.STATE_ACTIVE
 import android.view.Gravity
-import android.view.View
 import android.widget.LinearLayout
+import android.widget.RelativeLayout
 import com.android.systemui.R
 import com.android.systemui.plugins.qs.QSIconView
 import com.android.systemui.plugins.qs.QSTile
 import com.android.systemui.qs.tileimpl.QSTileImpl.getColorForState
 
-class QSTileViewHorizontal(
+// Placeholder
+private const val CORNER_RADIUS = 40f
+
+open class QSTileViewHorizontal(
     context: Context,
     icon: QSIconView
 ) : QSTileView(context, icon, false) {
 
-    private var paintDrawable: PaintDrawable? = null
-    private var divider: View? = null
+    protected var paintDrawable: PaintDrawable? = null
+    private var paintColor = Color.WHITE
+    private var paintAnimator: ValueAnimator? = null
 
     init {
         orientation = HORIZONTAL
@@ -49,7 +54,12 @@
 
     override fun createLabel() {
         super.createLabel()
-        findViewById<LinearLayout>(R.id.label_group)?.gravity = Gravity.START
+        findViewById<LinearLayout>(R.id.label_group)?.apply {
+            gravity = Gravity.START
+            (layoutParams as? RelativeLayout.LayoutParams)?.apply {
+                removeRule(RelativeLayout.ALIGN_PARENT_TOP)
+            }
+        }
         mLabel.gravity = Gravity.START
         mLabel.textDirection = TEXT_DIRECTION_LOCALE
         mSecondLine.gravity = Gravity.START
@@ -57,7 +67,7 @@
         val padding = context.resources.getDimensionPixelSize(R.dimen.qs_tile_side_label_padding)
         mLabelContainer.setPaddingRelative(0, padding, padding, padding)
         (mLabelContainer.layoutParams as LayoutParams).gravity =
-                Gravity.CENTER_VERTICAL or Gravity.START
+            Gravity.CENTER_VERTICAL or Gravity.START
     }
 
     override fun updateRippleSize() {
@@ -66,8 +76,8 @@
     override fun newTileBackground(): Drawable? {
         val d = super.newTileBackground()
         if (paintDrawable == null) {
-            paintDrawable = PaintDrawable(Color.WHITE).apply {
-                setCornerRadius(50f)
+            paintDrawable = PaintDrawable(paintColor).apply {
+                setCornerRadius(CORNER_RADIUS)
             }
         }
         if (d is RippleDrawable) {
@@ -90,10 +100,39 @@
 
     override fun handleStateChanged(state: QSTile.State) {
         super.handleStateChanged(state)
-        paintDrawable?.setTint(getCircleColor(state.state))
         mSecondLine.setTextColor(mLabel.textColors)
         mLabelContainer.background = null
-        divider?.backgroundTintList = mLabel.textColors
+
+        val allowAnimations = animationsEnabled() && paintColor != Color.WHITE
+        val newColor = getCircleColor(state.state)
+        if (allowAnimations) {
+            animateToNewState(newColor)
+        } else {
+            if (newColor != paintColor) {
+                clearAnimator()
+                paintDrawable?.paint?.color = newColor
+                paintDrawable?.invalidateSelf()
+            }
+        }
+        paintColor = newColor
+    }
+
+    private fun animateToNewState(newColor: Int) {
+        if (newColor != paintColor) {
+            clearAnimator()
+            paintAnimator = ValueAnimator.ofArgb(paintColor, newColor)
+                .setDuration(QSIconViewImpl.QS_ANIM_LENGTH).apply {
+                    addUpdateListener { animation: ValueAnimator ->
+                        paintDrawable?.paint?.color = animation.animatedValue as Int
+                        paintDrawable?.invalidateSelf()
+                    }
+                    start()
+                }
+        }
+    }
+
+    private fun clearAnimator() {
+        paintAnimator?.cancel()?.also { paintAnimator = null }
     }
 
     override fun handleExpand(dualTarget: Boolean) {}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
index 3841dac..70287cd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
@@ -16,10 +16,13 @@
 
 package com.android.systemui.qs.tiles;
 
-import static android.service.SensorPrivacyIndividualEnabledSensorProto.CAMERA;
+import static android.content.pm.PackageManager.FEATURE_CAMERA_TOGGLE;
+import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
 
 import static com.android.systemui.DejankUtils.whitelistIpcs;
 
+import android.hardware.SensorPrivacyManager;
+import android.hardware.SensorPrivacyManager.Sensors.Sensor;
 import android.os.Handler;
 import android.os.Looper;
 import android.provider.DeviceConfig;
@@ -58,8 +61,8 @@
 
     @Override
     public boolean isAvailable() {
-        return /*getHost().getContext().getPackageManager().hasSystemFeature(FEATURE_CAMERA_TOGGLE)
-                && */whitelistIpcs(() -> DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+        return getHost().getContext().getPackageManager().hasSystemFeature(FEATURE_CAMERA_TOGGLE)
+                && whitelistIpcs(() -> DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
                 "camera_toggle_enabled",
                 false));
     }
@@ -75,7 +78,7 @@
     }
 
     @Override
-    public int getSensorId() {
+    public @Sensor int getSensorId() {
         return CAMERA;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 1dddc45..f03ce2c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -54,6 +54,7 @@
 import com.android.systemui.statusbar.policy.HotspotController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.WifiIndicators;
 
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
@@ -269,13 +270,10 @@
     private final NetworkController.SignalCallback mSignalCallback =
             new NetworkController.SignalCallback() {
                 @Override
-                public void setWifiIndicators(boolean enabled,
-                        NetworkController.IconState statusIcon,
-                        NetworkController.IconState qsIcon, boolean activityIn, boolean activityOut,
-                        String description, boolean isTransient, String statusLabel) {
+                public void setWifiIndicators(WifiIndicators indicators) {
                     // statusIcon.visible has the connected status information
-                    boolean enabledAndConnected =
-                            enabled && (qsIcon == null ? false : qsIcon.visible);
+                    boolean enabledAndConnected = indicators.enabled
+                            && (indicators.qsIcon == null ? false : indicators.qsIcon.visible);
                     if (enabledAndConnected != mWifiConnected) {
                         mWifiConnected = enabledAndConnected;
                         // Hotspot is not connected, so changes here should update
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 720c5dc..6a574d1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -56,6 +56,7 @@
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
 
 import javax.inject.Inject;
@@ -264,21 +265,17 @@
         private final CallbackInfo mInfo = new CallbackInfo();
 
         @Override
-        public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
-                int qsType, boolean activityIn, boolean activityOut,
-                CharSequence typeContentDescription,
-                CharSequence typeContentDescriptionHtml, CharSequence description,
-                boolean isWide, int subId, boolean roaming, boolean showTriangle) {
-            if (qsIcon == null) {
+        public void setMobileDataIndicators(MobileDataIndicators indicators) {
+            if (indicators.qsIcon == null) {
                 // Not data sim, don't display.
                 return;
             }
             mInfo.dataSubscriptionName = mController.getMobileDataNetworkName();
-            mInfo.dataContentDescription =
-                    (description != null) ? typeContentDescriptionHtml : null;
-            mInfo.activityIn = activityIn;
-            mInfo.activityOut = activityOut;
-            mInfo.roaming = roaming;
+            mInfo.dataContentDescription = indicators.description != null
+                    ? indicators.typeContentDescriptionHtml : null;
+            mInfo.activityIn = indicators.activityIn;
+            mInfo.activityOut = indicators.activityOut;
+            mInfo.roaming = indicators.roaming;
             mInfo.multipleSubs = mController.getNumberSubscriptions() > 1;
             refreshState(mInfo);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
index 946d041..e1a1fd2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
@@ -51,7 +51,9 @@
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import com.android.systemui.statusbar.policy.NetworkController.WifiIndicators;
 import com.android.systemui.statusbar.policy.WifiIcons;
 
 import java.io.FileDescriptor;
@@ -234,70 +236,44 @@
 
 
         @Override
-        public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
-                boolean activityIn, boolean activityOut, String description, boolean isTransient,
-                String statusLabel) {
+        public void setWifiIndicators(WifiIndicators indicators) {
             if (DEBUG) {
-                Log.d(TAG, "setWifiIndicators: "
-                        + "enabled = " + enabled + ","
-                        + "statusIcon = " + (statusIcon == null ? "" : statusIcon.toString()) + ","
-                        + "qsIcon = " + (qsIcon == null ? "" : qsIcon.toString()) + ","
-                        + "activityIn = " + activityIn + ","
-                        + "activityOut = " + activityOut + ","
-                        + "description = " + description + ","
-                        + "isTransient = " + isTransient + ","
-                        + "statusLabel = " + statusLabel);
+                Log.d(TAG, "setWifiIndicators: " + indicators);
             }
-            mWifiInfo.mEnabled = enabled;
-            if (qsIcon == null) {
+            mWifiInfo.mEnabled = indicators.enabled;
+            if (indicators.qsIcon == null) {
                 return;
             }
-            mWifiInfo.mConnected = qsIcon.visible;
-            mWifiInfo.mWifiSignalIconId = qsIcon.icon;
-            mWifiInfo.mWifiSignalContentDescription = qsIcon.contentDescription;
-            mWifiInfo.mSsid = description;
-            mWifiInfo.mActivityIn = activityIn;
-            mWifiInfo.mActivityOut = activityOut;
-            mWifiInfo.mIsTransient = isTransient;
-            mWifiInfo.mStatusLabel = statusLabel;
+            mWifiInfo.mConnected = indicators.qsIcon.visible;
+            mWifiInfo.mWifiSignalIconId = indicators.qsIcon.icon;
+            mWifiInfo.mWifiSignalContentDescription = indicators.qsIcon.contentDescription;
+            mWifiInfo.mEnabled = indicators.enabled;
+            mWifiInfo.mSsid = indicators.description;
+            mWifiInfo.mActivityIn = indicators.activityIn;
+            mWifiInfo.mActivityOut = indicators.activityOut;
+            mWifiInfo.mIsTransient = indicators.isTransient;
+            mWifiInfo.mStatusLabel = indicators.statusLabel;
             refreshState(mWifiInfo);
         }
 
         @Override
-        public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
-                int qsType, boolean activityIn, boolean activityOut,
-                CharSequence typeContentDescription,
-                CharSequence typeContentDescriptionHtml, CharSequence description,
-                boolean isWide, int subId, boolean roaming, boolean showTriangle) {
+        public void setMobileDataIndicators(MobileDataIndicators indicators) {
             if (DEBUG) {
-                Log.d(TAG, "setMobileDataIndicators: "
-                        + "statusIcon = " + (statusIcon == null ? "" :  statusIcon.toString()) + ","
-                        + "qsIcon = " + (qsIcon == null ? "" : qsIcon.toString()) + ","
-                        + "statusType = " + statusType + ","
-                        + "qsType = " + qsType + ","
-                        + "activityIn = " + activityIn + ","
-                        + "activityOut = " + activityOut + ","
-                        + "typeContentDescription = " + typeContentDescription + ","
-                        + "typeContentDescriptionHtml = " + typeContentDescriptionHtml + ","
-                        + "description = " + description + ","
-                        + "isWide = " + isWide + ","
-                        + "subId = " + subId + ","
-                        + "roaming = " + roaming + ","
-                        + "showTriangle = " + showTriangle);
+                Log.d(TAG, "setMobileDataIndicators: " + indicators);
             }
-            if (qsIcon == null) {
+            if (indicators.qsIcon == null) {
                 // Not data sim, don't display.
                 return;
             }
-            mCellularInfo.mDataSubscriptionName =
-                    description == null ? mController.getMobileDataNetworkName() : description;
-            mCellularInfo.mDataContentDescription =
-                    (description != null) ? typeContentDescriptionHtml : null;
-            mCellularInfo.mMobileSignalIconId = qsIcon.icon;
-            mCellularInfo.mQsTypeIcon = qsType;
-            mCellularInfo.mActivityIn = activityIn;
-            mCellularInfo.mActivityOut = activityOut;
-            mCellularInfo.mRoaming = roaming;
+            mCellularInfo.mDataSubscriptionName = indicators.description == null
+                    ? mController.getMobileDataNetworkName() : indicators.description;
+            mCellularInfo.mDataContentDescription = indicators.description != null
+                    ? indicators.typeContentDescriptionHtml : null;
+            mCellularInfo.mMobileSignalIconId = indicators.qsIcon.icon;
+            mCellularInfo.mQsTypeIcon = indicators.qsType;
+            mCellularInfo.mActivityIn = indicators.activityIn;
+            mCellularInfo.mActivityOut = indicators.activityOut;
+            mCellularInfo.mRoaming = indicators.roaming;
             mCellularInfo.mMultipleSubs = mController.getNumberSubscriptions() > 1;
             refreshState(mCellularInfo);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
index 2f0071a..e9b712d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
@@ -16,10 +16,13 @@
 
 package com.android.systemui.qs.tiles;
 
-import static android.service.SensorPrivacyIndividualEnabledSensorProto.MICROPHONE;
+import static android.content.pm.PackageManager.FEATURE_MICROPHONE_TOGGLE;
+import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE;
 
 import static com.android.systemui.DejankUtils.whitelistIpcs;
 
+import android.hardware.SensorPrivacyManager;
+import android.hardware.SensorPrivacyManager.Sensors.Sensor;
 import android.os.Handler;
 import android.os.Looper;
 import android.provider.DeviceConfig;
@@ -58,7 +61,9 @@
 
     @Override
     public boolean isAvailable() {
-        return whitelistIpcs(() -> DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+        return getHost().getContext().getPackageManager()
+                .hasSystemFeature(FEATURE_MICROPHONE_TOGGLE)
+                && whitelistIpcs(() -> DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
                 "mic_toggle_enabled",
                 false));
     }
@@ -74,7 +79,7 @@
     }
 
     @Override
-    public int getSensorId() {
+    public @Sensor int getSensorId() {
         return MICROPHONE;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
index f94cabc..aec7b9a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
@@ -33,46 +33,39 @@
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
-import com.android.systemui.qs.SecureSetting;
+import com.android.systemui.qs.ReduceBrightColorsController;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
-import com.android.systemui.settings.UserTracker;
-import com.android.systemui.util.settings.SecureSettings;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 
 /** Quick settings tile: Reduce Bright Colors **/
-public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState> {
+public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState>
+        implements ReduceBrightColorsController.Listener{
 
     //TODO(b/170973645): get icon drawable
     private final Icon mIcon = null;
-    private final SecureSetting mActivatedSetting;
     private final boolean mIsAvailable;
+    private final ReduceBrightColorsController mReduceBrightColorsController;
+    private boolean mIsListening;
 
     @Inject
     public ReduceBrightColorsTile(
             @Named(RBC_AVAILABLE) boolean isAvailable,
+            ReduceBrightColorsController reduceBrightColorsController,
             QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
-            QSLogger qsLogger,
-            UserTracker userTracker,
-            SecureSettings secureSettings
+            QSLogger qsLogger
     ) {
         super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
                 activityStarter, qsLogger);
-
-        mActivatedSetting = new SecureSetting(secureSettings, mainHandler,
-                Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, userTracker.getUserId()) {
-            @Override
-            protected void handleValueChanged(int value, boolean observedChange) {
-                refreshState();
-            }
-        };
+        mReduceBrightColorsController = reduceBrightColorsController;
+        mReduceBrightColorsController.observe(getLifecycle(), this);
         mIsAvailable = isAvailable;
 
     }
@@ -84,7 +77,6 @@
     @Override
     protected void handleDestroy() {
         super.handleDestroy();
-        mActivatedSetting.setListening(false);
     }
 
     @Override
@@ -93,25 +85,13 @@
     }
 
     @Override
-    public void handleSetListening(boolean listening) {
-        super.handleSetListening(listening);
-        mActivatedSetting.setListening(listening);
-    }
-
-    @Override
-    protected void handleUserSwitch(int newUserId) {
-        mActivatedSetting.setUserId(newUserId);
-        refreshState();
-    }
-
-    @Override
     public Intent getLongClickIntent() {
         return new Intent(Settings.ACTION_REDUCE_BRIGHT_COLORS_SETTINGS);
     }
 
     @Override
     protected void handleClick() {
-        mActivatedSetting.setValue(mState.value ? 0 : 1);
+        mReduceBrightColorsController.setReduceBrightColorsActivated(!mState.value);
     }
 
     @Override
@@ -121,7 +101,7 @@
 
     @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
-        state.value = mActivatedSetting.getValue() == 1;
+        state.value = mReduceBrightColorsController.isReduceBrightColorsActivated();
         state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         state.label = mContext.getString(R.string.quick_settings_reduce_bright_colors_label);
         state.expandedAccessibilityClassName = Switch.class.getName();
@@ -132,4 +112,9 @@
     public int getMetricsCategory() {
         return 0;
     }
+
+    @Override
+    public void onActivated(boolean activated) {
+        refreshState();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
index 00703e7..0c582bd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
@@ -17,7 +17,7 @@
 package com.android.systemui.qs.tiles;
 
 import android.content.Intent;
-import android.hardware.SensorPrivacyManager.IndividualSensor;
+import android.hardware.SensorPrivacyManager.Sensors.Sensor;
 import android.os.Handler;
 import android.os.Looper;
 import android.service.quicksettings.Tile;
@@ -49,7 +49,7 @@
     /**
      * @return Id of the sensor that will be toggled
      */
-    public abstract @IndividualSensor int getSensorId();
+    public abstract @Sensor int getSensorId();
 
     /**
      * @return icon for the QS tile
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index a6fd011..341e67c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -51,8 +51,8 @@
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
-import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import com.android.systemui.statusbar.policy.NetworkController.WifiIndicators;
 import com.android.systemui.statusbar.policy.WifiIcons;
 import com.android.wifitrackerlib.WifiEntry;
 
@@ -303,22 +303,20 @@
         final CallbackInfo mInfo = new CallbackInfo();
 
         @Override
-        public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
-                boolean activityIn, boolean activityOut, String description, boolean isTransient,
-                String statusLabel) {
-            if (DEBUG) Log.d(TAG, "onWifiSignalChanged enabled=" + enabled);
-            if (qsIcon == null) {
+        public void setWifiIndicators(WifiIndicators indicators) {
+            if (DEBUG) Log.d(TAG, "onWifiSignalChanged enabled=" + indicators.enabled);
+            if (indicators.qsIcon == null) {
                 return;
             }
-            mInfo.enabled = enabled;
-            mInfo.connected = qsIcon.visible;
-            mInfo.wifiSignalIconId = qsIcon.icon;
-            mInfo.ssid = description;
-            mInfo.activityIn = activityIn;
-            mInfo.activityOut = activityOut;
-            mInfo.wifiSignalContentDescription = qsIcon.contentDescription;
-            mInfo.isTransient = isTransient;
-            mInfo.statusLabel = statusLabel;
+            mInfo.enabled = indicators.enabled;
+            mInfo.connected = indicators.qsIcon.visible;
+            mInfo.wifiSignalIconId = indicators.qsIcon.icon;
+            mInfo.ssid = indicators.description;
+            mInfo.activityIn = indicators.activityIn;
+            mInfo.activityOut = indicators.activityOut;
+            mInfo.wifiSignalContentDescription = indicators.qsIcon.contentDescription;
+            mInfo.isTransient = indicators.isTransient;
+            mInfo.statusLabel = indicators.statusLabel;
             if (isShowingDetail()) {
                 mDetailAdapter.updateItems();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java b/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java
index 53d9f1c..c066619 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java
@@ -65,6 +65,9 @@
     private float mTopDelta = 0f;
     private float mBottomDelta = 0f;
 
+    private int mExtraTopPadding;
+    private int mExtraBottomPadding;
+
     private CropBoundary mCurrentDraggingBoundary = CropBoundary.NONE;
     private float mStartingY;  // y coordinate of ACTION_DOWN
     private CropInteractionListener mCropInteractionListener;
@@ -117,12 +120,13 @@
                 if (mCurrentDraggingBoundary != CropBoundary.NONE) {
                     float delta = event.getY() - mStartingY;
                     if (mCurrentDraggingBoundary == CropBoundary.TOP) {
-                        mTopDelta = pixelsToFraction((int) MathUtils.constrain(delta, -topPx,
+                        mTopDelta = pixelDistanceToFraction((int) MathUtils.constrain(delta,
+                                -topPx + mExtraTopPadding,
                                 bottomPx - 2 * mCropTouchMargin - topPx));
                     } else {  // Bottom
-                        mBottomDelta = pixelsToFraction((int) MathUtils.constrain(delta,
+                        mBottomDelta = pixelDistanceToFraction((int) MathUtils.constrain(delta,
                                 topPx + 2 * mCropTouchMargin - bottomPx,
-                                getHeight() - bottomPx));
+                                getHeight() - bottomPx - mExtraBottomPadding));
                     }
                     updateListener(event);
                     invalidate();
@@ -140,6 +144,25 @@
     }
 
     /**
+     * Set the given boundary to the given value without animation.
+     */
+    public void setBoundaryTo(CropBoundary boundary, float value) {
+        switch (boundary) {
+            case TOP:
+                mTopCrop = value;
+                break;
+            case BOTTOM:
+                mBottomCrop = value;
+                break;
+            case NONE:
+                Log.w(TAG, "No boundary selected for animation");
+                break;
+        }
+
+        invalidate();
+    }
+
+    /**
      * Animate the given boundary to the given value.
      */
     public void animateBoundaryTo(CropBoundary boundary, float value) {
@@ -176,6 +199,16 @@
     }
 
     /**
+     * Set additional top and bottom padding for the image being cropped (used when the
+     * corresponding ImageView doesn't take the full height).
+     */
+    public void setExtraPadding(int top, int bottom) {
+        mExtraTopPadding = top;
+        mExtraBottomPadding = bottom;
+        invalidate();
+    }
+
+    /**
      * @return value [0,1] representing the position of the top crop boundary. Does not reflect
      * changes from any in-progress touch input.
      */
@@ -225,12 +258,22 @@
                 true, mHandlePaint);
     }
 
+    /**
+     * Convert the given fraction position to pixel position within the View.
+     */
     private int fractionToPixels(float frac) {
-        return (int) (frac * getHeight());
+        return (int) (mExtraTopPadding + frac * getImageHeight());
     }
 
-    private float pixelsToFraction(int px) {
-        return px / (float) getHeight();
+    private int getImageHeight() {
+        return getHeight() - mExtraTopPadding - mExtraBottomPadding;
+    }
+
+    /**
+     * Convert the given pixel distance to fraction of the image.
+     */
+    private float pixelDistanceToFraction(int px) {
+        return px / (float) getImageHeight();
     }
 
     private CropBoundary nearestBoundary(MotionEvent event, int topPx, int bottomPx) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
index 89efda9..4dc846e 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
@@ -20,8 +20,17 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.HardwareRenderer;
+import android.graphics.RecordingCanvas;
+import android.graphics.Rect;
+import android.graphics.RenderNode;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Log;
@@ -33,6 +42,14 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.time.ZonedDateTime;
+import java.util.UUID;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
@@ -44,9 +61,21 @@
 public class LongScreenshotActivity extends Activity {
     private static final String TAG = "LongScreenshotActivity";
 
+    private static final String IMAGE_PATH_KEY = "saved-image";
+    private static final String TOP_BOUNDARY_KEY = "top-boundary";
+    private static final String BOTTOM_BOUNDARY_KEY = "bottom-boundary";
+
     private final UiEventLogger mUiEventLogger;
     private final ScrollCaptureController mScrollCaptureController;
     private final ScrollCaptureClient.Connection mConnection;
+    private final Executor mUiExecutor;
+    private final Executor mBackgroundExecutor;
+    private final ImageExporter mImageExporter;
+
+    private String mSavedImagePath;
+    // If true, the activity is re-loading an image from storage, which should either succeed and
+    // populate the UI or fail and finish the activity.
+    private boolean mRestoringInstance;
 
     private ImageView mPreview;
     private View mSave;
@@ -69,6 +98,9 @@
             @Background Executor bgExecutor,
             Context context) {
         mUiEventLogger = uiEventLogger;
+        mUiExecutor = mainExecutor;
+        mBackgroundExecutor = bgExecutor;
+        mImageExporter = imageExporter;
 
         mScrollCaptureController = new ScrollCaptureController(context, mainExecutor, bgExecutor,
                 imageExporter);
@@ -95,12 +127,45 @@
         mCancel.setOnClickListener(this::onClicked);
         mEdit.setOnClickListener(this::onClicked);
         mShare.setOnClickListener(this::onClicked);
+
+        if (savedInstanceState != null) {
+            String imagePath = savedInstanceState.getString(IMAGE_PATH_KEY);
+            if (!TextUtils.isEmpty(imagePath)) {
+                mRestoringInstance = true;
+                mBackgroundExecutor.execute(() -> {
+                    Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
+                    if (bitmap == null) {
+                        Log.e(TAG, "Failed to read bitmap from " + imagePath);
+                        finishAndRemoveTask();
+                    } else {
+                        runOnUiThread(() -> {
+                            BitmapDrawable drawable = new BitmapDrawable(getResources(), bitmap);
+                            mPreview.setImageDrawable(drawable);
+                            mMagnifierView.setDrawable(drawable, bitmap.getWidth(),
+                                    bitmap.getHeight());
+
+                            mCropView.setBoundaryTo(CropView.CropBoundary.TOP,
+                                    savedInstanceState.getFloat(TOP_BOUNDARY_KEY, 0f));
+                            mCropView.setBoundaryTo(CropView.CropBoundary.BOTTOM,
+                                    savedInstanceState.getFloat(BOTTOM_BOUNDARY_KEY, 1f));
+                            mRestoringInstance = false;
+                            // Reuse the same path for subsequent restoration.
+                            mSavedImagePath = imagePath;
+                            Log.d(TAG, "Loaded bitmap from " + imagePath);
+                        });
+                    }
+                });
+            }
+        }
+        mPreview.addOnLayoutChangeListener(
+                (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
+                        updateCropLocation());
     }
 
     @Override
     public void onStart() {
         super.onStart();
-        if (mPreview.getDrawable() == null) {
+        if (mPreview.getDrawable() == null && !mRestoringInstance) {
             if (mConnection == null) {
                 Log.e(TAG, "Failed to get scroll capture connection, bailing out");
                 finishAndRemoveTask();
@@ -110,6 +175,24 @@
         }
     }
 
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putString(IMAGE_PATH_KEY, mSavedImagePath);
+        outState.putFloat(TOP_BOUNDARY_KEY, mCropView.getTopBoundary());
+        outState.putFloat(BOTTOM_BOUNDARY_KEY, mCropView.getBottomBoundary());
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        if (isFinishing() && !TextUtils.isEmpty(mSavedImagePath)) {
+            Log.d(TAG, "Deleting " + mSavedImagePath);
+            File file = new File(mSavedImagePath);
+            file.delete();
+        }
+    }
+
     private void setButtonsEnabled(boolean enabled) {
         mSave.setEnabled(enabled);
         mCancel.setEnabled(enabled);
@@ -161,50 +244,111 @@
     }
 
     private void startExport(PendingAction action) {
-        mScrollCaptureController.startExport(mCropView.getTopBoundary(),
-                mCropView.getBottomBoundary(), new ScrollCaptureController.ExportCallback() {
-                    @Override
-                    public void onError() {
-                        Log.e(TAG, "Error exporting image data.");
-                        setButtonsEnabled(true);
-                    }
+        Drawable drawable = mPreview.getDrawable();
 
-                    @Override
-                    public void onExportComplete(Uri outputUri) {
-                        setButtonsEnabled(true);
-                        switch (action) {
-                            case EDIT:
-                                doEdit(outputUri);
-                                break;
-                            case SHARE:
-                                doShare(outputUri);
-                                break;
-                            case SAVE:
-                                // Nothing more to do
-                                finishAndRemoveTask();
-                                break;
-                        }
-                    }
-                });
+        Rect croppedPortion = new Rect(
+                0,
+                (int) (drawable.getIntrinsicHeight() * mCropView.getTopBoundary()),
+                drawable.getIntrinsicWidth(),
+                (int) (drawable.getIntrinsicHeight() * mCropView.getBottomBoundary()));
+        ListenableFuture<ImageExporter.Result> exportFuture = mImageExporter.export(
+                mBackgroundExecutor, UUID.randomUUID(), getBitmap(croppedPortion, drawable),
+                ZonedDateTime.now());
+        exportFuture.addListener(() -> {
+            try {
+                ImageExporter.Result result = exportFuture.get();
+                setButtonsEnabled(true);
+                switch (action) {
+                    case EDIT:
+                        doEdit(result.uri);
+                        break;
+                    case SHARE:
+                        doShare(result.uri);
+                        break;
+                    case SAVE:
+                        // Nothing more to do
+                        finishAndRemoveTask();
+                        break;
+                }
+            } catch (InterruptedException | ExecutionException e) {
+                Log.e(TAG, "failed to export", e);
+                setButtonsEnabled(true);
+            }
+        }, mUiExecutor);
+    }
+
+    private Bitmap getBitmap(Rect bounds, Drawable drawable) {
+        final RenderNode output = new RenderNode("Bitmap Export");
+        output.setPosition(0, 0, bounds.width(), bounds.height());
+        RecordingCanvas canvas = output.beginRecording();
+        // Translating the canvas instead of setting drawable bounds since the drawable is still
+        // used in the preview.
+        canvas.translate(0, -bounds.top);
+        drawable.draw(canvas);
+        output.endRecording();
+        return HardwareRenderer.createHardwareBitmap(output, bounds.width(), bounds.height());
+    }
+
+    private void saveCacheBitmap(ImageTileSet tileSet) {
+        long startTime = SystemClock.uptimeMillis();
+        Bitmap bitmap = tileSet.toBitmap();
+        // TODO(b/181562529) Remove this
+        mPreview.setImageDrawable(tileSet.getDrawable());
+        try {
+            File file = File.createTempFile("long_screenshot", ".png", null);
+            FileOutputStream stream = new FileOutputStream(file);
+            bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
+            stream.flush();
+            stream.close();
+            mSavedImagePath = file.getAbsolutePath();
+            Log.d(TAG, "Saved to " + file.getAbsolutePath() + " in "
+                    + (SystemClock.uptimeMillis() - startTime) + "ms");
+        } catch (IOException e) {
+            Log.e(TAG, "Failed to save bitmap", e);
+        }
+    }
+
+    private void updateCropLocation() {
+        Drawable drawable = mPreview.getDrawable();
+        if (drawable == null) {
+            return;
+        }
+
+        float imageRatio = drawable.getBounds().width() / (float) drawable.getBounds().height();
+        float viewRatio = mPreview.getWidth() / (float) mPreview.getHeight();
+
+        if (imageRatio > viewRatio) {
+            // Image is full width and height is constrained, compute extra padding to inform
+            // CropView
+            float imageHeight = mPreview.getHeight() * viewRatio / imageRatio;
+            int extraPadding = (int) (mPreview.getHeight() - imageHeight) / 2;
+            mCropView.setExtraPadding(extraPadding, extraPadding);
+        } else {
+            // Image is full height
+            mCropView.setExtraPadding(0, 0);
+        }
     }
 
     private void doCapture() {
         mScrollCaptureController.start(mConnection,
                 new ScrollCaptureController.ScrollCaptureCallback() {
-            @Override
-            public void onError() {
-                Log.e(TAG, "Error!");
-                finishAndRemoveTask();
-            }
+                    @Override
+                    public void onError() {
+                        Log.e(TAG, "Error capturing long screenshot!");
+                        finishAndRemoveTask();
+                    }
 
-            @Override
-            public void onComplete(ImageTileSet imageTileSet) {
-                Log.i(TAG, "Got tiles " + imageTileSet.getWidth() + " x "
-                        + imageTileSet.getHeight());
-                mPreview.setImageDrawable(imageTileSet.getDrawable());
-                mMagnifierView.setImageTileset(imageTileSet);
-                mCropView.animateBoundaryTo(CropView.CropBoundary.BOTTOM, 0.5f);
-            }
-        });
+                    @Override
+                    public void onComplete(ImageTileSet imageTileSet) {
+                        Log.i(TAG, "Got tiles " + imageTileSet.getWidth() + " x "
+                                + imageTileSet.getHeight());
+                        mPreview.setImageDrawable(imageTileSet.getDrawable());
+                        updateCropLocation();
+                        mMagnifierView.setDrawable(imageTileSet.getDrawable(),
+                                imageTileSet.getWidth(), imageTileSet.getHeight());
+                        mCropView.animateBoundaryTo(CropView.CropBoundary.BOTTOM, 0.5f);
+                        mBackgroundExecutor.execute(() -> saveCacheBitmap(imageTileSet));
+                    }
+                });
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java b/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java
index f8f1d3a..90f3042 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.screenshot;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.annotation.NonNull;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
@@ -27,6 +30,7 @@
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewPropertyAnimator;
 
 import androidx.annotation.Nullable;
 
@@ -34,7 +38,7 @@
 
 /**
  * MagnifierView shows a full-res cropped circular display of a given ImageTileSet, contents and
- * positioning dereived from events from a CropView to which it listens.
+ * positioning derived from events from a CropView to which it listens.
  *
  * Not meant to be a general-purpose magnifier!
  */
@@ -56,6 +60,20 @@
     private float mLastCropPosition;
     private CropView.CropBoundary mCropBoundary;
 
+    private ViewPropertyAnimator mTranslationAnimator;
+    private final Animator.AnimatorListener mTranslationAnimatorListener =
+            new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            mTranslationAnimator = null;
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mTranslationAnimator = null;
+        }
+    };
+
     public MagnifierView(Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, 0);
     }
@@ -77,13 +95,12 @@
         mCheckerboardPaint.setColor(Color.GRAY);
     }
 
-    public void setImageTileset(ImageTileSet tiles) {
-        if (tiles != null) {
-            mDrawable = tiles.getDrawable();
-            mDrawable.setBounds(0, 0, tiles.getWidth(), tiles.getHeight());
-        } else {
-            mDrawable = null;
-        }
+    /**
+     * Set the drawable to be displayed by the magnifier.
+     */
+    public void setDrawable(@NonNull Drawable drawable, int width, int height) {
+        mDrawable = drawable;
+        mDrawable.setBounds(0, 0, width, height);
         invalidate();
     }
 
@@ -133,6 +150,8 @@
     public void onCropMotionEvent(MotionEvent event, CropView.CropBoundary boundary,
             float cropPosition, int cropPositionPx) {
         mCropBoundary = boundary;
+        boolean touchOnRight = event.getX() > getParentWidth() / 2;
+        float translateXTarget = touchOnRight ? 0 : getParentWidth() - getWidth();
         switch (event.getAction()) {
             case MotionEvent.ACTION_DOWN:
                 mLastCropPosition = cropPosition;
@@ -144,11 +163,22 @@
                 setAlpha(0f);
                 setTranslationX((getParentWidth() - getWidth()) / 2);
                 setVisibility(View.VISIBLE);
-                boolean touchOnRight = event.getX() > getParentWidth() / 2;
-                float translateXTarget = touchOnRight ? 0 : getParentWidth() - getWidth();
-                animate().alpha(1f).translationX(translateXTarget).scaleX(1f).scaleY(1f).start();
+                mTranslationAnimator =
+                        animate().alpha(1f).translationX(translateXTarget).scaleX(1f).scaleY(1f);
+                mTranslationAnimator.setListener(mTranslationAnimatorListener);
+                mTranslationAnimator.start();
                 break;
             case MotionEvent.ACTION_MOVE:
+                // The touch is near the middle if it's within 10% of the center point.
+                // We don't want to animate horizontally if the touch is near the middle.
+                boolean nearMiddle = Math.abs(event.getX() - getParentWidth() / 2)
+                        < getParentWidth() / 10f;
+                boolean viewOnLeft = getTranslationX() < (getParentWidth() - getWidth()) / 2;
+                if (!nearMiddle && viewOnLeft != touchOnRight && mTranslationAnimator == null) {
+                    mTranslationAnimator = animate().translationX(translateXTarget);
+                    mTranslationAnimator.setListener(mTranslationAnimatorListener);
+                    mTranslationAnimator.start();
+                }
                 mLastCropPosition = cropPosition;
                 setTranslationY(cropPositionPx - getHeight() / 2);
                 invalidate();
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 131fde6..3d6dea3 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -325,6 +325,7 @@
 
         attachWindow();
         mWindow.setContentView(mScreenshotView);
+        mScreenshotView.requestApplyInsets();
 
         mScreenshotView.takePartialScreenshot(
                 rect -> takeScreenshotInternal(finisher, rect));
@@ -518,7 +519,7 @@
         setWindowFocusable(true);
 
         if (mConfigProxy.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.SCREENSHOT_SCROLLING_ENABLED, false)) {
+                SystemUiDeviceConfigFlags.SCREENSHOT_SCROLLING_ENABLED, true)) {
             View decorView = mWindow.getDecorView();
 
             // Wait until this window is attached to request because it is
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
index dc639dc..54b99bb 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
@@ -21,24 +21,25 @@
 import static java.lang.Math.min;
 import static java.util.Objects.requireNonNull;
 
+import android.annotation.BinderThread;
 import android.annotation.UiContext;
 import android.app.ActivityTaskManager;
 import android.content.Context;
 import android.graphics.PixelFormat;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.hardware.HardwareBuffer;
 import android.media.Image;
 import android.media.ImageReader;
 import android.os.IBinder;
+import android.os.ICancellationSignal;
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.IScrollCaptureCallbacks;
 import android.view.IScrollCaptureConnection;
 import android.view.IWindowManager;
+import android.view.ScrollCaptureResponse;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.view.ScrollCaptureViewSupport;
 
 import java.util.function.Consumer;
 
@@ -62,16 +63,19 @@
      */
     public interface Connection {
         /**
-         * Session start should be deferred until UI is active because of resource allocation and
-         * potential visible side effects in the target window.
-         *
+         * Start a session.
+
          * @param sessionConsumer listener to receive the session once active
          * @param maxPages the capture buffer size expressed as a multiple of the content height
          */
+        // TODO ListenableFuture
         void start(Consumer<Session> sessionConsumer, float maxPages);
 
         /**
-         * Close the connection.
+         * Close the connection. Must end capture if started to avoid potential unwanted visual
+         * artifacts.
+         *
+         * @see Session#end(Runnable)
          */
         void close();
     }
@@ -119,6 +123,7 @@
          * @param top the top (y) position of the tile to capture, in content rect space
          * @param consumer listener to be informed of the result
          */
+        // TODO ListenableFuture
         void requestTile(int top, Consumer<CaptureResult> consumer);
 
         /**
@@ -129,16 +134,31 @@
          */
         int getMaxTiles();
 
+        /**
+         * @return the height of each image tile
+         */
         int getTileHeight();
 
+        /**
+         * @return the height of scrollable content being captured
+         */
         int getPageHeight();
 
+        /**
+         * @return the width of the scrollable page
+         */
         int getPageWidth();
 
         /**
+         * @return the bounds on screen of the window being captured.
+         */
+        Rect getWindowBounds();
+
+        /**
          * End the capture session, return the target app to original state. The listener
          * will be called when the target app is ready to before visible and interactive.
          */
+        // TODO ListenableFuture
         void end(Runnable listener);
     }
 
@@ -185,13 +205,13 @@
                         + ", taskId=" + taskId + ", consumer=" + consumer + ")");
             }
             mWindowManagerService.requestScrollCapture(displayId, mHostWindowToken, taskId,
-                    new ControllerCallbacks(consumer));
+                    new ClientCallbacks(consumer));
         } catch (RemoteException e) {
             Log.e(TAG, "Ignored remote exception", e);
         }
     }
 
-    private static class ControllerCallbacks extends IScrollCaptureCallbacks.Stub implements
+    private static class ClientCallbacks extends IScrollCaptureCallbacks.Stub implements
             Connection, Session, IBinder.DeathRecipient {
 
         private IScrollCaptureConnection mConnection;
@@ -206,46 +226,63 @@
         private int mTileWidth;
         private Rect mRequestRect;
         private boolean mStarted;
+
+        private ICancellationSignal mCancellationSignal;
+        private Rect mWindowBounds;
+        private Rect mBoundsInWindow;
         private int mMaxTiles;
 
-        private ControllerCallbacks(Consumer<Connection> connectionConsumer) {
+        private ClientCallbacks(Consumer<Connection> connectionConsumer) {
             mConnectionConsumer = connectionConsumer;
         }
 
-        // IScrollCaptureCallbacks
-
+        @BinderThread
         @Override
-        public void onConnected(IScrollCaptureConnection connection, Rect scrollBounds,
-                Point positionInWindow) throws RemoteException {
+        public void onScrollCaptureResponse(ScrollCaptureResponse response) throws RemoteException {
             if (DEBUG_SCROLL) {
-                Log.d(TAG, "onConnected(connection=" + connection + ", scrollBounds=" + scrollBounds
-                        + ", positionInWindow=" + positionInWindow + ")");
+                Log.d(TAG, "onScrollCaptureResponse(response=" + response + ")");
             }
-            mConnection = connection;
-            mConnection.asBinder().linkToDeath(this, 0);
-            mScrollBounds = scrollBounds;
-            mConnectionConsumer.accept(this);
+            if (response.isConnected()) {
+                mConnection = response.getConnection();
+                mConnection.asBinder().linkToDeath(this, 0);
+                mWindowBounds = response.getWindowBounds();
+                mBoundsInWindow = response.getBoundsInWindow();
+
+                int pxPerPage = mBoundsInWindow.width() * mBoundsInWindow.height();
+                int pxPerTile = min(TILE_SIZE_PX_MAX, (pxPerPage / TILES_PER_PAGE));
+                mTileWidth = mBoundsInWindow.width();
+                mTileHeight = pxPerTile  / mBoundsInWindow.width();
+                if (DEBUG_SCROLL) {
+                    Log.d(TAG, "boundsInWindow: " + mBoundsInWindow);
+                    Log.d(TAG, "tile size: " + mTileWidth + "x" + mTileHeight);
+                    Log.d(TAG, "maxHeight: " + (mMaxTiles * mTileHeight) + "px");
+                }
+                mConnectionConsumer.accept(this);
+            }
             mConnectionConsumer = null;
-
-            int pxPerPage = mScrollBounds.width() * mScrollBounds.height();
-            int pxPerTile = min(TILE_SIZE_PX_MAX, (pxPerPage / TILES_PER_PAGE));
-            mTileWidth = mScrollBounds.width();
-            mTileHeight = pxPerTile  / mScrollBounds.width();
-            if (DEBUG_SCROLL) {
-                Log.d(TAG, "scrollBounds: " + mScrollBounds);
-                Log.d(TAG, "tile dimen: " + mTileWidth + "x" + mTileHeight);
-            }
         }
 
         @Override
-        public void onUnavailable() throws RemoteException {
+        public void start(Consumer<Session> sessionConsumer, float maxPages) {
             if (DEBUG_SCROLL) {
-                Log.d(TAG, "onUnavailable");
+                Log.d(TAG, "start(sessionConsumer=" + sessionConsumer + ","
+                        + " maxPages=" + maxPages + ")");
             }
-            // The targeted app does not support scroll capture
-            // or the window could not be found... etc etc.
+            mMaxTiles = (int) Math.ceil(maxPages * TILES_PER_PAGE);
+            mReader = ImageReader.newInstance(mTileWidth, mTileHeight, PixelFormat.RGBA_8888,
+                    mMaxTiles, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
+            mSessionConsumer = sessionConsumer;
+
+            try {
+                mCancellationSignal = mConnection.startCapture(mReader.getSurface());
+                mStarted = true;
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed to start", e);
+                mReader.close();
+            }
         }
 
+        @BinderThread
         @Override
         public void onCaptureStarted() {
             if (DEBUG_SCROLL) {
@@ -256,13 +293,25 @@
         }
 
         @Override
-        public void onCaptureBufferSent(long frameNumber, Rect contentArea) {
-            Image image = null;
-            if (frameNumber != ScrollCaptureViewSupport.NO_FRAME_PRODUCED) {
-                image = mReader.acquireNextImage();
-            }
+        public void requestTile(int top, Consumer<CaptureResult> consumer) {
             if (DEBUG_SCROLL) {
-                Log.d(TAG, "onCaptureBufferSent(frameNumber=" + frameNumber
+                Log.d(TAG, "requestTile(top=" + top + ", consumer=" + consumer + ")");
+            }
+            cancelPendingRequest();
+            mRequestRect = new Rect(0, top, mTileWidth, top + mTileHeight);
+            mResultConsumer = consumer;
+            try {
+                mCancellationSignal = mConnection.requestImage(mRequestRect);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Caught remote exception from requestImage", e);
+            }
+        }
+
+        @Override
+        public void onImageRequestCompleted(int flags, Rect contentArea) {
+            Image image = mReader.acquireLatestImage();
+            if (DEBUG_SCROLL) {
+                Log.d(TAG, "onCaptureBufferSent(flags=" + flags
                         + ", contentArea=" + contentArea + ") image=" + image);
             }
             // Save and clear first, since the consumer will likely request the next
@@ -273,61 +322,13 @@
         }
 
         @Override
-        public void onConnectionClosed() {
-            if (DEBUG_SCROLL) {
-                Log.d(TAG, "onConnectionClosed()");
-            }
-            disconnect();
-            if (mShutdownListener != null) {
-                mShutdownListener.run();
-                mShutdownListener = null;
-            }
-        }
-
-        // Misc
-
-        private void disconnect() {
-            if (mConnection != null) {
-                mConnection.asBinder().unlinkToDeath(this, 0);
-            }
-            mConnection = null;
-        }
-
-        // ScrollCaptureController.Connection
-
-        @Override
-        public void start(Consumer<Session> sessionConsumer, float maxPages) {
-            if (DEBUG_SCROLL) {
-                Log.d(TAG, "start(sessionConsumer=" + sessionConsumer + ","
-                        + " maxPages=" + maxPages + ")"
-                        + " [maxHeight: " + (mMaxTiles * mTileHeight) + "px]");
-            }
-            mMaxTiles = (int) Math.ceil(maxPages * TILES_PER_PAGE);
-            mReader = ImageReader.newInstance(mTileWidth, mTileHeight, PixelFormat.RGBA_8888,
-                    mMaxTiles, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
-            mSessionConsumer = sessionConsumer;
-            try {
-                mConnection.startCapture(mReader.getSurface());
-                mStarted = true;
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed to start", e);
-            }
-        }
-
-        @Override
-        public void close() {
-            end(null);
-        }
-
-        // ScrollCaptureController.Session
-
-        @Override
         public void end(Runnable listener) {
             if (DEBUG_SCROLL) {
                 Log.d(TAG, "end(listener=" + listener + ")");
             }
             if (mStarted) {
                 mShutdownListener = listener;
+                mReader.close();
                 try {
                     // listener called from onConnectionClosed callback
                     mConnection.endCapture();
@@ -342,40 +343,37 @@
             }
         }
 
+        @BinderThread
         @Override
-        public int getPageHeight() {
-            return mScrollBounds.height();
-        }
-
-        @Override
-        public int getPageWidth() {
-            return mScrollBounds.width();
-        }
-
-        @Override
-        public int getTileHeight() {
-            return mTileHeight;
-        }
-
-        @Override
-        public int getMaxTiles() {
-            return mMaxTiles;
-        }
-
-        @Override
-        public void requestTile(int top, Consumer<CaptureResult> consumer) {
-            if (DEBUG_SCROLL) {
-                Log.d(TAG, "requestTile(top=" + top + ", consumer=" + consumer + ")");
+        public void onCaptureEnded() {
+            close();
+            if (mShutdownListener != null) {
+                mShutdownListener.run();
+                mShutdownListener = null;
             }
-            mRequestRect = new Rect(0, top, mTileWidth, top + mTileHeight);
-            mResultConsumer = consumer;
-            try {
-                mConnection.requestImage(mRequestRect);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Caught remote exception from requestImage", e);
+        }
+
+        @Override
+        public void close() {
+            if (mConnection != null) {
+                try {
+                    mConnection.close();
+                } catch (RemoteException e) {
+                    /* ignore */
+                }
+                disconnect();
             }
         }
 
+        // Misc
+
+        private void disconnect() {
+            if (mConnection != null) {
+                mConnection.asBinder().unlinkToDeath(this, 0);
+            }
+            mConnection = null;
+        }
+
         /**
          * The process hosting the window went away abruptly!
          */
@@ -386,5 +384,40 @@
             }
             disconnect();
         }
+
+        @Override
+        public int getPageHeight() {
+            return mBoundsInWindow.height();
+        }
+
+        @Override
+        public int getPageWidth() {
+            return mBoundsInWindow.width();
+        }
+
+        @Override
+        public int getTileHeight() {
+            return mTileHeight;
+        }
+
+        public Rect getWindowBounds() {
+            return new Rect(mWindowBounds);
+        }
+
+        @Override
+        public int getMaxTiles() {
+            return mMaxTiles;
+        }
+
+        private void cancelPendingRequest() {
+            if (mCancellationSignal != null) {
+                try {
+                    mCancellationSignal.cancel();
+                } catch (RemoteException e) {
+                    /* ignore */
+                }
+                mCancellationSignal = null;
+            }
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
index 4a3ffa45..9da6b8f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
@@ -18,7 +18,6 @@
 
 import android.annotation.UiThread;
 import android.content.Context;
-import android.graphics.Rect;
 import android.net.Uri;
 import android.provider.Settings;
 import android.util.Log;
@@ -27,11 +26,8 @@
 import com.android.systemui.screenshot.ScrollCaptureClient.Connection;
 import com.android.systemui.screenshot.ScrollCaptureClient.Session;
 
-import com.google.common.util.concurrent.ListenableFuture;
-
 import java.time.ZonedDateTime;
 import java.util.UUID;
-import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 
 /**
@@ -42,13 +38,15 @@
     private static final float MAX_PAGES_DEFAULT = 3f;
 
     private static final String SETTING_KEY_MAX_PAGES = "screenshot.scroll_max_pages";
+    // Portion of the tiles to be acquired above the starting position in infinite scroll
+    // situations. 1.0 means maximize the area above, 0 means just go down.
+    private static final float IDEAL_PORTION_ABOVE = 0.4f;
 
-    private static final int UP = -1;
-    private static final int DOWN = 1;
+    private boolean mScrollingUp = true;
+    // If true, stop acquiring images when no more bitmap data is available in the current direction
+    // or if the desired bitmap size is reached.
+    private boolean mFinishOnBoundary;
 
-    private int mDirection = DOWN;
-    private boolean mAtBottomEdge;
-    private boolean mAtTopEdge;
     private Session mSession;
 
     public static final int MAX_HEIGHT = 12000;
@@ -89,31 +87,9 @@
         connection.start(this::startCapture, maxPages);
     }
 
-    /**
-     * @param topCrop    [0,1) fraction of the top of the image to be cropped out.
-     * @param bottomCrop (0, 1] fraction to be cropped out, e.g. 0.7 will crop out the bottom 30%.
-     */
-    public void startExport(float topCrop, float bottomCrop, ExportCallback callback) {
-        Rect croppedPortion = new Rect(
-                0,
-                (int) (mImageTileSet.getHeight() * topCrop),
-                mImageTileSet.getWidth(),
-                (int) (mImageTileSet.getHeight() * bottomCrop));
-        ListenableFuture<ImageExporter.Result> exportFuture = mImageExporter.export(
-                mBgExecutor, mRequestId, mImageTileSet.toBitmap(croppedPortion), mCaptureTime);
-        exportFuture.addListener(() -> {
-            try {
-                ImageExporter.Result result = exportFuture.get();
-                callback.onExportComplete(result.uri);
-            } catch (InterruptedException | ExecutionException e) {
-                Log.e(TAG, "failed to export", e);
-                callback.onError();
-            }
-        }, mUiExecutor);
-    }
-
     private void onCaptureResult(CaptureResult result) {
-        Log.d(TAG, "onCaptureResult: " + result);
+        Log.d(TAG, "onCaptureResult: " + result + " scrolling up: " + mScrollingUp
+                + " finish on boundary: " + mFinishOnBoundary);
         boolean emptyResult = result.captured.height() == 0;
         boolean partialResult = !emptyResult
                 && result.captured.height() < result.requested.height();
@@ -121,34 +97,28 @@
 
         if (partialResult || emptyResult) {
             // Potentially reached a vertical boundary. Extend in the other direction.
-            switch (mDirection) {
-                case DOWN:
-                    Log.d(TAG, "Reached bottom edge.");
-                    mAtBottomEdge = true;
-                    mDirection = UP;
-                    break;
-                case UP:
-                    Log.d(TAG, "Reached top edge.");
-                    mAtTopEdge = true;
-                    mDirection = DOWN;
-                    break;
-            }
-
-            if (mAtTopEdge && mAtBottomEdge) {
-                Log.d(TAG, "Reached both top and bottom edge, ending.");
+            if (mFinishOnBoundary) {
                 finish = true;
             } else {
-                // only reverse if the edge was relatively close to the starting point
-                if (mImageTileSet.getHeight() < mSession.getPageHeight() * 3) {
-                    Log.d(TAG, "Restarting in reverse direction.");
-
-                    // Because of temporary limitations, we cannot just jump to the opposite edge
-                    // and continue there. Instead, clear the results and start over capturing from
-                    // here in the other direction.
-                    mImageTileSet.clear();
-                } else {
-                    Log.d(TAG, "Capture is tall enough, stopping here.");
-                    finish = true;
+                // We hit a boundary, clear the tiles, capture everything in the opposite direction,
+                // then finish.
+                mImageTileSet.clear();
+                mFinishOnBoundary = true;
+                mScrollingUp = !mScrollingUp;
+            }
+        } else {
+            // Got the full requested result, but may have got enough bitmap data now
+            int expectedTiles = mImageTileSet.size() + 1;
+            boolean hitMaxTiles = expectedTiles >= mSession.getMaxTiles();
+            if (hitMaxTiles && mFinishOnBoundary) {
+                finish = true;
+            } else {
+                if (mScrollingUp) {
+                    if (expectedTiles >= mSession.getMaxTiles() * IDEAL_PORTION_ABOVE) {
+                        // We got enough above the start point, now see how far down it can go.
+                        mImageTileSet.clear();
+                        mScrollingUp = false;
+                    }
                 }
             }
         }
@@ -163,9 +133,8 @@
 
 
         // Stop when "too tall"
-        if (mImageTileSet.size() >= mSession.getMaxTiles()
-                || mImageTileSet.getHeight() > MAX_HEIGHT) {
-            Log.d(TAG, "Max height and/or tile count reached.");
+        if (mImageTileSet.getHeight() > MAX_HEIGHT) {
+            Log.d(TAG, "Max height reached.");
             finish = true;
         }
 
@@ -177,8 +146,8 @@
             return;
         }
 
-        int nextTop = (mDirection == DOWN) ? result.captured.bottom
-                : result.captured.top - mSession.getTileHeight();
+        int nextTop = (mScrollingUp)
+                ? result.captured.top - mSession.getTileHeight() : result.captured.bottom;
         Log.d(TAG, "requestTile: " + nextTop);
         mSession.requestTile(nextTop, /* consumer */ this::onCaptureResult);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
index 9f182e1..6586137 100644
--- a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
@@ -25,8 +25,8 @@
 import android.content.res.Resources
 import android.hardware.SensorPrivacyManager
 import android.hardware.SensorPrivacyManager.EXTRA_SENSOR
-import android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_CAMERA
-import android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE
+import android.hardware.SensorPrivacyManager.Sensors.CAMERA
+import android.hardware.SensorPrivacyManager.Sensors.MICROPHONE
 import android.os.Bundle
 import android.os.Handler
 import android.text.Html
@@ -81,7 +81,7 @@
                 dismiss()
             }
         }
-        if (!sensorPrivacyManager.isIndividualSensorPrivacyEnabled(sensor)) {
+        if (!sensorPrivacyManager.isSensorPrivacyEnabled(sensor)) {
             finish()
             return
         }
@@ -89,9 +89,9 @@
         mAlertParams.apply {
             try {
                 mMessage = Html.fromHtml(getString(when (sensor) {
-                    INDIVIDUAL_SENSOR_MICROPHONE ->
+                    MICROPHONE ->
                         R.string.sensor_privacy_start_use_mic_dialog_content
-                    INDIVIDUAL_SENSOR_CAMERA ->
+                    CAMERA ->
                         R.string.sensor_privacy_start_use_camera_dialog_content
                     else -> Resources.ID_NULL
                 }, packageManager.getApplicationInfo(sensorUsePackageName, 0)
@@ -102,9 +102,9 @@
             }
 
             mIconId = when (sensor) {
-                INDIVIDUAL_SENSOR_MICROPHONE ->
+                MICROPHONE ->
                     com.android.internal.R.drawable.perm_group_microphone
-                INDIVIDUAL_SENSOR_CAMERA -> com.android.internal.R.drawable.perm_group_camera
+                CAMERA -> com.android.internal.R.drawable.perm_group_camera
                 else -> Resources.ID_NULL
             }
 
@@ -121,7 +121,7 @@
     override fun onStart() {
         super.onStart()
 
-        sensorPrivacyManager.suppressIndividualSensorPrivacyReminders(sensorUsePackageName, true)
+        sensorPrivacyManager.suppressSensorPrivacyReminders(sensorUsePackageName, true)
         unsuppressImmediately = false
     }
 
@@ -156,11 +156,11 @@
 
         if (unsuppressImmediately) {
             sensorPrivacyManager
-                    .suppressIndividualSensorPrivacyReminders(sensorUsePackageName, false)
+                    .suppressSensorPrivacyReminders(sensorUsePackageName, false)
         } else {
             Handler(mainLooper).postDelayed({
                 sensorPrivacyManager
-                        .suppressIndividualSensorPrivacyReminders(sensorUsePackageName, false)
+                        .suppressSensorPrivacyReminders(sensorUsePackageName, false)
             }, SUPPRESS_REMINDERS_REMOVAL_DELAY_MILLIS)
         }
     }
@@ -170,7 +170,7 @@
     }
 
     private fun disableSensorPrivacy() {
-        sensorPrivacyManager.setIndividualSensorPrivacyForProfileGroup(sensor, false)
+        sensorPrivacyManager.setSensorPrivacyForProfileGroup(sensor, false)
         unsuppressImmediately = true
         setResult(RESULT_OK)
     }
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
index 0bfc8e5..fea521f 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
@@ -72,8 +72,6 @@
     private static final Uri BRIGHTNESS_FOR_VR_FLOAT_URI =
             Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_FOR_VR_FLOAT);
 
-    private final float mMinimumBacklight;
-    private final float mMaximumBacklight;
     private final float mDefaultBacklight;
     private final float mMinimumBacklightForVr;
     private final float mMaximumBacklightForVr;
@@ -314,10 +312,6 @@
 
         mDisplayId = mContext.getDisplayId();
         PowerManager pm = context.getSystemService(PowerManager.class);
-        mMinimumBacklight = pm.getBrightnessConstraint(
-                PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM);
-        mMaximumBacklight = pm.getBrightnessConstraint(
-                PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM);
         mDefaultBacklight = mContext.getDisplay().getBrightnessDefault();
         mMinimumBacklightForVr = pm.getBrightnessConstraint(
                 PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM_VR);
@@ -375,8 +369,8 @@
             metric = mAutomatic
                     ? MetricsEvent.ACTION_BRIGHTNESS_AUTO
                     : MetricsEvent.ACTION_BRIGHTNESS;
-            minBacklight = mMinimumBacklight;
-            maxBacklight = mMaximumBacklight;
+            minBacklight = PowerManager.BRIGHTNESS_MIN;
+            maxBacklight = PowerManager.BRIGHTNESS_MAX;
             settingToChange = Settings.System.SCREEN_BRIGHTNESS_FLOAT;
         }
         final float valFloat = MathUtils.min(convertGammaToLinearFloat(value,
@@ -439,8 +433,8 @@
             min = mMinimumBacklightForVr;
             max = mMaximumBacklightForVr;
         } else {
-            min = mMinimumBacklight;
-            max = mMaximumBacklight;
+            min = PowerManager.BRIGHTNESS_MIN;
+            max = PowerManager.BRIGHTNESS_MAX;
         }
         // convertGammaToLinearFloat returns 0-1
         if (BrightnessSynchronizer.floatEquals(brightnessValue,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
index cf77e29..1d59257 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
@@ -86,4 +86,8 @@
     public boolean isNavigationBarOverlayEnabled() {
         return mFlagReader.isEnabled(R.bool.flag_navigation_bar_overlay);
     }
+
+    public boolean isPMLiteEnabled() {
+        return mFlagReader.isEnabled(R.bool.flag_pm_lite);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java b/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java
index 9ed9659..f2adaf0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java
@@ -207,7 +207,7 @@
             sb.append(g.toJson());
             count++;
         }
-        mLastSaveLen += count;
+        mLastSaveLen = count;
         sb.append("]");
         return sb.toString();
     }
@@ -249,9 +249,7 @@
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         save();
         if (mLastSaveLen >= 0) {
-            pw.println(String.valueOf(mLastSaveLen)
-                    + " gestures since last dump written to " + mLogfile);
-            mLastSaveLen = 0;
+            pw.println(String.valueOf(mLastSaveLen) + " gestures written to " + mLogfile);
         } else {
             pw.println("error writing gestures");
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 7e2d27a..a4e97a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar;
 
+import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
 import static android.view.View.GONE;
 import static android.view.View.VISIBLE;
 
@@ -41,6 +42,7 @@
 import android.content.IntentFilter;
 import android.content.pm.UserInfo;
 import android.content.res.ColorStateList;
+import android.content.res.Resources;
 import android.graphics.Color;
 import android.hardware.biometrics.BiometricSourceType;
 import android.hardware.face.FaceManager;
@@ -277,10 +279,7 @@
         // avoid calling this method since it has an IPC
         if (whitelistIpcs(this::isOrganizationOwnedDevice)) {
             final CharSequence organizationName = getOrganizationOwnedDeviceOrganizationName();
-            final CharSequence disclosure =  organizationName != null
-                    ? mContext.getResources().getString(R.string.do_disclosure_with_name,
-                    organizationName)
-                    : mContext.getResources().getText(R.string.do_disclosure_generic);
+            final CharSequence disclosure = getDisclosureText(organizationName);
             mRotateTextViewController.updateIndication(
                     INDICATION_TYPE_DISCLOSURE,
                     new KeyguardIndication.Builder()
@@ -297,6 +296,22 @@
         }
     }
 
+    private CharSequence getDisclosureText(@Nullable CharSequence organizationName) {
+        final Resources packageResources = mContext.getResources();
+        if (organizationName == null) {
+            return packageResources.getText(R.string.do_disclosure_generic);
+        } else if (mDevicePolicyManager.isDeviceManaged()
+                && mDevicePolicyManager.getDeviceOwnerType(
+                mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser())
+                == DEVICE_OWNER_TYPE_FINANCED) {
+            return packageResources.getString(R.string.do_financed_disclosure_with_name,
+                    organizationName);
+        } else {
+            return packageResources.getString(R.string.do_disclosure_with_name,
+                    organizationName);
+        }
+    }
+
     private void updateOwnerInfo() {
         if (!isKeyguardLayoutEnabled()) {
             mRotateTextViewController.hideIndication(INDICATION_TYPE_OWNER_INFO);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 01d3103..e5a960e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -83,6 +83,9 @@
     public static final int STATE_DOT = 1;
     public static final int STATE_HIDDEN = 2;
 
+    /** Maximum allowed width or height for an icon drawable */
+    private static final int MAX_IMAGE_SIZE = 500;
+
     private static final String TAG = "StatusBarIconView";
     private static final Property<StatusBarIconView, Float> ICON_APPEAR_AMOUNT
             = new FloatProperty<StatusBarIconView>("iconAppearAmount") {
@@ -378,6 +381,13 @@
             Log.w(TAG, "No icon for slot " + mSlot + "; " + mIcon.icon);
             return false;
         }
+
+        if (drawable.getIntrinsicWidth() > MAX_IMAGE_SIZE
+                || drawable.getIntrinsicHeight() > MAX_IMAGE_SIZE) {
+            Log.w(TAG, "Drawable is too large " + mIcon);
+            return false;
+        }
+
         if (withClear) {
             setImageDrawable(null);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 7c3b791..c8c0755 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -548,8 +548,6 @@
         try {
             mStatusBarService.onNotificationClear(
                     notification.getPackageName(),
-                    notification.getTag(),
-                    notification.getId(),
                     notification.getUser().getIdentifier(),
                     notification.getKey(),
                     dismissedByUserStats.dismissalSurface,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index d617dff..6b96ee4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -254,8 +254,6 @@
                 try {
                     mStatusBarService.onNotificationClear(
                             entry.getSbn().getPackageName(),
-                            entry.getSbn().getTag(),
-                            entry.getSbn().getId(),
                             entry.getSbn().getUser().getIdentifier(),
                             entry.getSbn().getKey(),
                             stats.dismissalSurface,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
index 0ad6507..dff97a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.notification.init
 
+import android.content.Context
+import android.provider.Settings
 import android.service.notification.StatusBarNotification
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.people.widget.PeopleSpaceWidgetManager
@@ -58,6 +60,7 @@
  */
 @SysUISingleton
 class NotificationsControllerImpl @Inject constructor(
+    private val context: Context,
     private val featureFlags: FeatureFlags,
     private val notificationListener: NotificationListener,
     private val entryManager: NotificationEntryManager,
@@ -129,7 +132,9 @@
             entryManager.attach(notificationListener)
         }
 
-        if (featureFlags.isPeopleTileEnabled) {
+        val showPeopleSpace = Settings.Global.getInt(context.contentResolver,
+                Settings.Global.SHOW_PEOPLE_SPACE, 1)
+        if (showPeopleSpace == 1) {
             peopleSpaceWidgetManager.attach(notificationListener)
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index f427ba9..b0b91bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -17,15 +17,13 @@
 package com.android.systemui.statusbar.notification.row;
 
 
-import static android.provider.Settings.Global.NOTIFICATION_BUBBLES;
-import static android.provider.Settings.Secure.SHOW_NOTIFICATION_SNOOZE;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
@@ -34,6 +32,7 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Pair;
+import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.NotificationHeaderView;
@@ -1238,6 +1237,7 @@
         mCachedHeadsUpRemoteInput = null;
     }
 
+
     private RemoteInputView applyRemoteInput(View view, NotificationEntry entry,
             boolean hasRemoteInput, PendingIntent existingPendingIntent,
             RemoteInputView cachedView, NotificationViewWrapper wrapper) {
@@ -1275,6 +1275,15 @@
                 if (color == Notification.COLOR_DEFAULT) {
                     color = mContext.getColor(R.color.default_remote_input_background);
                 }
+                if (mContext.getResources().getBoolean(
+                        com.android.internal.R.bool.config_tintNotificationsWithTheme)) {
+                    Resources.Theme theme = new ContextThemeWrapper(mContext,
+                            com.android.internal.R.style.Theme_DeviceDefault_DayNight).getTheme();
+                    TypedArray ta = theme.obtainStyledAttributes(
+                            new int[]{com.android.internal.R.attr.colorAccent});
+                    color = ta.getColor(0, color);
+                    ta.recycle();
+                }
                 existing.setBackgroundColor(ContrastColorUtil.ensureTextBackgroundColor(color,
                         mContext.getColor(R.color.remote_input_text_enabled),
                         mContext.getColor(R.color.remote_input_hint)));
@@ -1317,7 +1326,7 @@
 
     private boolean isBubblesEnabled() {
         return Settings.Global.getInt(mContext.getContentResolver(),
-                NOTIFICATION_BUBBLES, 0) == 1;
+                Settings.Global.NOTIFICATION_BUBBLES, 0) == 1;
     }
 
     /**
@@ -1346,12 +1355,10 @@
                 && isPersonWithShortcut
                 && entry.getBubbleMetadata() != null;
         if (showButton) {
-            Drawable d = mContext.getResources().getDrawable(entry.isBubble()
+            // explicitly resolve drawable resource using SystemUI's theme
+            Drawable d = mContext.getDrawable(entry.isBubble()
                     ? R.drawable.bubble_ic_stop_bubble
                     : R.drawable.bubble_ic_create_bubble);
-            mContainingNotification.updateNotificationColor();
-            final int tint = mContainingNotification.getNotificationColor();
-            d.setTint(tint);
 
             String contentDescription = mContext.getResources().getString(entry.isBubble()
                     ? R.string.notification_conversation_unbubble
@@ -1373,27 +1380,25 @@
         }
         ImageView snoozeButton = layout.findViewById(com.android.internal.R.id.snooze_button);
         View actionContainer = layout.findViewById(com.android.internal.R.id.actions_container);
-        LinearLayout actionContainerLayout =
-                layout.findViewById(com.android.internal.R.id.actions_container_layout);
-        if (snoozeButton == null || actionContainer == null || actionContainerLayout == null) {
+        if (snoozeButton == null || actionContainer == null) {
             return;
         }
         final boolean showSnooze = Settings.Secure.getInt(mContext.getContentResolver(),
-                SHOW_NOTIFICATION_SNOOZE, 0) == 1;
-        if (!showSnooze) {
+                Settings.Secure.SHOW_NOTIFICATION_SNOOZE, 0) == 1;
+        // Notification.Builder can 'disable' the snooze button to prevent it from being shown here
+        boolean snoozeDisabled = !snoozeButton.isEnabled();
+        if (!showSnooze || snoozeDisabled) {
             snoozeButton.setVisibility(GONE);
             return;
         }
 
-        Resources res = mContext.getResources();
-        Drawable snoozeDrawable = res.getDrawable(R.drawable.ic_snooze);
-        mContainingNotification.updateNotificationColor();
-        snoozeDrawable.setTint(mContainingNotification.getNotificationColor());
+        // explicitly resolve drawable resource using SystemUI's theme
+        Drawable snoozeDrawable = mContext.getDrawable(R.drawable.ic_snooze);
         snoozeButton.setImageDrawable(snoozeDrawable);
 
         final NotificationSnooze snoozeGuts = (NotificationSnooze) LayoutInflater.from(mContext)
                 .inflate(R.layout.notification_snooze, null, false);
-        final String snoozeDescription = res.getString(
+        final String snoozeDescription = mContext.getString(
                 R.string.notification_menu_snooze_description);
         final NotificationMenuRowPlugin.MenuItem snoozeMenuItem =
                 new NotificationMenuRow.NotificationMenuItem(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java
index 414d620..222735a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java
@@ -49,7 +49,7 @@
 
         // Custom views will most likely use just white or black as their text color.
         // We need to scan through and replace these colors by Material NEXT colors.
-        ensureThemeOnChildren();
+        ensureThemeOnChildren(mView);
 
         // Let's invert the notification colors when we're in night mode and
         // the notification background isn't colorized.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java
index 301c372..d21ae13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java
@@ -64,7 +64,7 @@
 
         // Custom views will most likely use just white or black as their text color.
         // We need to scan through and replace these colors by Material NEXT colors.
-        ensureThemeOnChildren();
+        ensureThemeOnChildren(mWrappedView);
 
         if (needsInversion(resolveBackgroundColor(), mWrappedView)) {
             invertViewLuminosity(mWrappedView);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index 5fff8c8..89babf0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -36,12 +36,12 @@
 import android.view.ViewGroup;
 import android.widget.TextView;
 
-import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.ColorUtils;
 import com.android.internal.util.ContrastColorUtil;
 import com.android.internal.widget.CachingIconView;
 import com.android.settingslib.Utils;
+import com.android.systemui.R;
 import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.TransformableView;
 import com.android.systemui.statusbar.notification.TransformState;
@@ -58,9 +58,11 @@
     private final Rect mTmpRect = new Rect();
 
     protected int mBackgroundColor = 0;
-    private int mLightTextColor;
-    private int mDarkTextColor;
-    private int mDefaultTextColor;
+    private int mMaterialTextColorPrimary;
+    private int mMaterialTextColorSecondary;
+    private int mThemedTextColorPrimary;
+    private int mThemedTextColorSecondary;
+    private boolean mAdjustTheme;
 
     public static NotificationViewWrapper wrap(Context ctx, View v, ExpandableNotificationRow row) {
         if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) {
@@ -97,6 +99,8 @@
         mView = view;
         mRow = row;
         onReinflated();
+        mAdjustTheme = ctx.getResources().getBoolean(
+                R.bool.config_adjustThemeOnNotificationCustomViews);
     }
 
     /**
@@ -121,15 +125,22 @@
             mBackgroundColor = backgroundColor;
             mView.setBackground(new ColorDrawable(Color.TRANSPARENT));
         }
-        mLightTextColor = mView.getContext().getColor(
-                com.android.internal.R.color.notification_primary_text_color_light);
-        mDarkTextColor = mView.getContext().getColor(
-                R.color.notification_primary_text_color_dark);
+
+        Context materialTitleContext = new ContextThemeWrapper(mView.getContext(),
+                com.android.internal.R.style.TextAppearance_Material_Notification_Title);
+        mMaterialTextColorPrimary = Utils.getColorAttr(materialTitleContext,
+                com.android.internal.R.attr.textColor).getDefaultColor();
+        Context materialContext = new ContextThemeWrapper(mView.getContext(),
+                com.android.internal.R.style.TextAppearance_Material_Notification);
+        mMaterialTextColorSecondary = Utils.getColorAttr(materialContext,
+                com.android.internal.R.attr.textColor).getDefaultColor();
 
         Context themedContext = new ContextThemeWrapper(mView.getContext(),
-                R.style.Theme_DeviceDefault_DayNight);
-        mDefaultTextColor = Utils.getColorAttr(themedContext, R.attr.textColorPrimary)
-                .getDefaultColor();
+                com.android.internal.R.style.Theme_DeviceDefault_DayNight);
+        mThemedTextColorPrimary = Utils.getColorAttr(themedContext,
+                com.android.internal.R.attr.textColorPrimary).getDefaultColor();
+        mThemedTextColorSecondary = Utils.getColorAttr(themedContext,
+                com.android.internal.R.attr.textColorSecondary).getDefaultColor();
     }
 
     protected boolean needsInversion(int defaultBackgroundColor, View view) {
@@ -207,38 +218,35 @@
         return false;
     }
 
-    protected void ensureThemeOnChildren() {
-        if (mView == null) {
+    protected void ensureThemeOnChildren(View rootView) {
+        if (!mAdjustTheme || mView == null || rootView == null) {
             return;
         }
 
         // Notifications with custom backgrounds should not be adjusted
         if (mBackgroundColor != Color.TRANSPARENT
-                || getBackgroundColor(mView) != Color.TRANSPARENT) {
+                || getBackgroundColor(mView) != Color.TRANSPARENT
+                || getBackgroundColor(rootView) != Color.TRANSPARENT) {
             return;
         }
 
         // Now let's check if there's unprotected text somewhere, and apply the theme if we find it.
-        if (!(mView instanceof ViewGroup)) {
-            return;
-        }
-        processChildrenTextColor((ViewGroup) mView);
+        processTextColorRecursive(rootView);
     }
 
-    private void processChildrenTextColor(ViewGroup viewGroup) {
-        if (viewGroup == null) {
-            return;
-        }
-
-        for (int i = 0; i < viewGroup.getChildCount(); i++) {
-            View child = viewGroup.getChildAt(i);
-            if (child instanceof TextView) {
-                int foreground = ((TextView) child).getCurrentTextColor();
-                if (foreground == mLightTextColor || foreground == mDarkTextColor) {
-                    ((TextView) child).setTextColor(mDefaultTextColor);
-                }
-            } else if (child instanceof ViewGroup) {
-                processChildrenTextColor((ViewGroup) child);
+    private void processTextColorRecursive(View view) {
+        if (view instanceof TextView) {
+            TextView textView = (TextView) view;
+            int foreground = textView.getCurrentTextColor();
+            if (foreground == mMaterialTextColorPrimary) {
+                textView.setTextColor(mThemedTextColorPrimary);
+            } else if (foreground == mMaterialTextColorSecondary) {
+                textView.setTextColor(mThemedTextColorSecondary);
+            }
+        } else if (view instanceof ViewGroup) {
+            ViewGroup viewGroup = (ViewGroup) view;
+            for (int i = 0; i < viewGroup.getChildCount(); i++) {
+                processTextColorRecursive(viewGroup.getChildAt(i));
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 3833637..3739424 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -20,10 +20,12 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.graphics.drawable.ColorDrawable;
 import android.service.notification.StatusBarNotification;
 import android.util.AttributeSet;
 import android.util.Pair;
+import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.NotificationHeaderView;
 import android.view.View;
@@ -33,6 +35,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.widget.CachingIconView;
+import com.android.internal.widget.NotificationExpandButton;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.NotificationGroupingUtil;
@@ -103,6 +106,8 @@
     private ViewGroup mCurrentHeader;
     private boolean mIsConversation;
 
+    private boolean mTintWithThemeAccent;
+    private boolean mShowGroupCountInExpander;
     private boolean mShowDividersWhenExpanded;
     private boolean mHideDividersDuringExpand;
     private int mTranslationForHeader;
@@ -145,6 +150,10 @@
                 com.android.internal.R.dimen.notification_content_margin);
         mEnableShadowOnChildNotifications =
                 res.getBoolean(R.bool.config_enableShadowOnChildNotifications);
+        mTintWithThemeAccent =
+                res.getBoolean(com.android.internal.R.bool.config_tintNotificationsWithTheme);
+        mShowGroupCountInExpander =
+                res.getBoolean(R.bool.config_showNotificationGroupCountInExpander);
         mShowDividersWhenExpanded =
                 res.getBoolean(R.bool.config_showDividersWhenGroupNotificationExpanded);
         mHideDividersDuringExpand =
@@ -229,7 +238,6 @@
             mNotificationHeader.measure(widthMeasureSpec, headerHeightSpec);
         }
         if (mNotificationHeaderLowPriority != null) {
-            headerHeightSpec = MeasureSpec.makeMeasureSpec(mHeaderHeight, MeasureSpec.EXACTLY);
             mNotificationHeaderLowPriority.measure(widthMeasureSpec, headerHeightSpec);
         }
 
@@ -397,7 +405,20 @@
         mGroupingUtil.updateChildrenAppearance();
     }
 
+    private void setExpandButtonNumber(NotificationViewWrapper wrapper) {
+        View expandButton = wrapper == null
+                ? null : wrapper.getExpandButton();
+        if (expandButton instanceof NotificationExpandButton) {
+            ((NotificationExpandButton) expandButton).setNumber(mUntruncatedChildCount);
+        }
+    }
+
     public void updateGroupOverflow() {
+        if (mShowGroupCountInExpander) {
+            setExpandButtonNumber(mNotificationHeaderWrapper);
+            setExpandButtonNumber(mNotificationHeaderWrapperLowPriority);
+            return;
+        }
         int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true /* likeCollapsed */);
         if (mUntruncatedChildCount > maxAllowedVisibleChildren) {
             int number = mUntruncatedChildCount - maxAllowedVisibleChildren;
@@ -1201,8 +1222,21 @@
     }
 
     public void onNotificationUpdated() {
-        mHybridGroupManager.setOverflowNumberColor(mOverflowNumber,
-                mContainingNotification.getNotificationColor());
+        if (mShowGroupCountInExpander) {
+            // The overflow number is not used, so its color is irrelevant; skip this
+            return;
+        }
+        int color = mContainingNotification.getNotificationColor();
+        if (mTintWithThemeAccent) {
+            // We're using the theme accent, color with the accent color instead of the notif color
+            Resources.Theme theme = new ContextThemeWrapper(mContext,
+                    com.android.internal.R.style.Theme_DeviceDefault_DayNight).getTheme();
+            TypedArray ta = theme.obtainStyledAttributes(
+                    new int[]{com.android.internal.R.attr.colorAccent});
+            color = ta.getColor(0, color);
+            ta.recycle();
+        }
+        mHybridGroupManager.setOverflowNumberColor(mOverflowNumber, color);
     }
 
     public int getPositionInLinearLayout(View childInGroup) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index e40c262..204dd9f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -14,6 +14,8 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.android.systemui.qs.dagger.QSFlagsModule.RBC_AVAILABLE;
+
 import android.content.Context;
 import android.content.res.Resources;
 import android.hardware.display.ColorDisplayManager;
@@ -27,6 +29,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.qs.AutoAddTracker;
 import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.ReduceBrightColorsController;
 import com.android.systemui.qs.SecureSetting;
 import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.statusbar.policy.CastController;
@@ -41,6 +44,8 @@
 import java.util.ArrayList;
 import java.util.Objects;
 
+import javax.inject.Named;
+
 /**
  * Manages which tiles should be automatically added to QS.
  */
@@ -69,6 +74,8 @@
     private final ManagedProfileController mManagedProfileController;
     private final NightDisplayListener mNightDisplayListener;
     private final CastController mCastController;
+    private final ReduceBrightColorsController mReduceBrightColorsController;
+    private final boolean mIsReduceBrightColorsAvailable;
     private final ArrayList<AutoAddSetting> mAutoAddSettingList = new ArrayList<>();
 
     public AutoTileManager(Context context, AutoAddTracker.Builder autoAddTrackerBuilder,
@@ -79,7 +86,9 @@
             DataSaverController dataSaverController,
             ManagedProfileController managedProfileController,
             NightDisplayListener nightDisplayListener,
-            CastController castController) {
+            CastController castController,
+            ReduceBrightColorsController reduceBrightColorsController,
+            @Named(RBC_AVAILABLE) boolean isReduceBrightColorsAvailable) {
         mContext = context;
         mHost = host;
         mSecureSettings = secureSettings;
@@ -91,6 +100,8 @@
         mManagedProfileController = managedProfileController;
         mNightDisplayListener = nightDisplayListener;
         mCastController = castController;
+        mReduceBrightColorsController = reduceBrightColorsController;
+        mIsReduceBrightColorsAvailable = isReduceBrightColorsAvailable;
     }
 
     /**
@@ -124,9 +135,9 @@
         if (!mAutoTracker.isAdded(CAST)) {
             mCastController.addCallback(mCastCallback);
         }
-
-        // TODO(b/170970675): Set a listener/controller and callback for Reduce Bright Colors
-        // state changes. Call into ColorDisplayService to get availability/config status
+        if (!mAutoTracker.isAdded(BRIGHTNESS) && mIsReduceBrightColorsAvailable) {
+            mReduceBrightColorsController.addCallback(mReduceBrightColorsCallback);
+        }
 
         int settingsN = mAutoAddSettingList.size();
         for (int i = 0; i < settingsN; i++) {
@@ -143,6 +154,9 @@
         if (ColorDisplayManager.isNightDisplayAvailable(mContext)) {
             mNightDisplayListener.setCallback(null);
         }
+        if (mIsReduceBrightColorsAvailable) {
+            mReduceBrightColorsController.removeCallback(mReduceBrightColorsCallback);
+        }
         mCastController.removeCallback(mCastCallback);
         int settingsN = mAutoAddSettingList.size();
         for (int i = 0; i < settingsN; i++) {
@@ -287,6 +301,24 @@
     };
 
     @VisibleForTesting
+    final ReduceBrightColorsController.Listener mReduceBrightColorsCallback =
+            new ReduceBrightColorsController.Listener() {
+                @Override
+                public void onActivated(boolean activated) {
+                    if (activated) {
+                        addReduceBrightColorsTile();
+                    }
+                }
+
+                private void addReduceBrightColorsTile() {
+                    if (mAutoTracker.isAdded(BRIGHTNESS)) return;
+                    mHost.addTile(BRIGHTNESS);
+                    mAutoTracker.setTileAdded(BRIGHTNESS);
+                    mHandler.post(() -> mReduceBrightColorsController.removeCallback(this));
+                }
+            };
+
+    @VisibleForTesting
     final CastController.Callback mCastCallback = new CastController.Callback() {
         @Override
         public void onCastDevicesChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 986333c..80109cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -19,7 +19,6 @@
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
 import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
-import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE;
 import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
 import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_BUTTON;
 import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_UNLOCK;
@@ -74,10 +73,6 @@
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.assist.AssistManager;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.controls.dagger.ControlsComponent;
-import com.android.systemui.controls.ui.ControlsDialog;
-import com.android.systemui.controls.ui.ControlsUiController;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.IntentButtonProvider;
 import com.android.systemui.plugins.IntentButtonProvider.IntentButton;
@@ -130,7 +125,7 @@
 
     private KeyguardAffordanceView mRightAffordanceView;
     private KeyguardAffordanceView mLeftAffordanceView;
-    private ImageView mAltLeftButton;
+    private ImageView mWalletButton;
     private ViewGroup mIndicationArea;
     private TextView mIndicationText;
     private TextView mIndicationTextBottom;
@@ -179,11 +174,7 @@
     private int mBurnInXOffset;
     private int mBurnInYOffset;
     private ActivityIntentHelper mActivityIntentHelper;
-
-    private ControlsDialog mControlsDialog;
-    private ControlsComponent mControlsComponent;
     private int mLockScreenMode;
-    private BroadcastDispatcher mBroadcastDispatcher;
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
 
     public KeyguardBottomAreaView(Context context) {
@@ -251,7 +242,7 @@
         mOverlayContainer = findViewById(R.id.overlay_container);
         mRightAffordanceView = findViewById(R.id.camera_button);
         mLeftAffordanceView = findViewById(R.id.left_button);
-        mAltLeftButton = findViewById(R.id.alt_left_button);
+        mWalletButton = findViewById(R.id.wallet_button);
         mIndicationArea = findViewById(R.id.keyguard_indication_area);
         mIndicationText = findViewById(R.id.keyguard_indication_text);
         mIndicationTextBottom = findViewById(R.id.keyguard_indication_text_bottom);
@@ -351,10 +342,10 @@
         mLeftAffordanceView.setLayoutParams(lp);
         updateLeftAffordanceIcon();
 
-        lp = mAltLeftButton.getLayoutParams();
+        lp = mWalletButton.getLayoutParams();
         lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_width);
         lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_height);
-        mAltLeftButton.setLayoutParams(lp);
+        mWalletButton.setLayoutParams(lp);
     }
 
     private void updateRightAffordanceIcon() {
@@ -427,11 +418,11 @@
         mLeftAffordanceView.setContentDescription(state.contentDescription);
     }
 
-    private void updateControlsVisibility() {
-        if (mDozing || mControlsComponent.getVisibility() != AVAILABLE) {
-            mAltLeftButton.setVisibility(GONE);
+    private void updateWalletVisibility() {
+        if (mDozing) {
+            mWalletButton.setVisibility(GONE);
         } else {
-            mAltLeftButton.setVisibility(VISIBLE);
+            mWalletButton.setVisibility(VISIBLE);
         }
     }
 
@@ -699,8 +690,8 @@
 
     public void startFinishDozeAnimation() {
         long delay = 0;
-        if (mAltLeftButton.getVisibility() == View.VISIBLE) {
-            startFinishDozeAnimationElement(mAltLeftButton, delay);
+        if (mWalletButton.getVisibility() == View.VISIBLE) {
+            startFinishDozeAnimationElement(mWalletButton, delay);
         }
         if (mLeftAffordanceView.getVisibility() == View.VISIBLE) {
             startFinishDozeAnimationElement(mLeftAffordanceView, delay);
@@ -774,14 +765,10 @@
 
         updateCameraVisibility();
         updateLeftAffordanceIcon();
-        updateControlsVisibility();
+        updateWalletVisibility();
 
         if (dozing) {
             mOverlayContainer.setVisibility(INVISIBLE);
-            if (mControlsDialog != null) {
-                mControlsDialog.dismiss();
-                mControlsDialog = null;
-            }
         } else {
             mOverlayContainer.setVisibility(VISIBLE);
             if (animate) {
@@ -811,7 +798,7 @@
         mLeftAffordanceView.setAlpha(alpha);
         mRightAffordanceView.setAlpha(alpha);
         mIndicationArea.setAlpha(alpha);
-        mAltLeftButton.setAlpha(alpha);
+        mWalletButton.setAlpha(alpha);
     }
 
     private class DefaultLeftButton implements IntentButton {
@@ -884,38 +871,18 @@
         return insets;
     }
 
-    /**
-     * Show or hide controls, depending on the lock screen mode and controls
-     * availability.
-     */
-    public void setupControls(ControlsComponent component, BroadcastDispatcher dispatcher) {
-        mControlsComponent = component;
-        mBroadcastDispatcher = dispatcher;
-        setupControls();
-    }
-
-    private void setupControls() {
+    private void setupWallet() {
         boolean inNewLayout = mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
         boolean settingEnabled = Settings.Global.getInt(mContext.getContentResolver(),
                 "controls_lockscreen", 0) == 1;
-        if (!inNewLayout || !settingEnabled || !mControlsComponent.isEnabled()) {
-            mAltLeftButton.setVisibility(View.GONE);
+        if (!inNewLayout || !settingEnabled) {
+            mWalletButton.setVisibility(View.GONE);
             return;
         }
 
-        mControlsComponent.getControlsListingController().get()
-                .addCallback(list -> {
-                    if (!list.isEmpty()) {
-                        mAltLeftButton.setImageDrawable(list.get(0).loadIcon());
-                        mAltLeftButton.setOnClickListener((v) -> {
-                            ControlsUiController ui = mControlsComponent
-                                    .getControlsUiController().get();
-                            mControlsDialog = new ControlsDialog(mContext, mBroadcastDispatcher)
-                                    .show(ui);
-                        });
-                    }
-                    updateControlsVisibility();
-                });
+        // TODO: add image
+        //        mWalletButton.setImageDrawable(list.get(0).loadIcon());
+        updateWalletVisibility();
     }
 
     /**
@@ -923,6 +890,6 @@
      */
     public void onLockScreenModeChanged(int mode) {
         mLockScreenMode = mode;
-        setupControls();
+        setupWallet();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 2ce4037..d638019 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -89,7 +89,8 @@
     private int mNotificationStackHeight;
 
     /**
-     * Minimum top margin to avoid overlap with status bar.
+     * Minimum top margin to avoid overlap with status bar, lock icon, or multi-user switcher
+     * avatar.
      */
     private int mMinTopMargin;
 
@@ -186,15 +187,15 @@
     /**
      * Sets up algorithm values.
      */
-    public void setup(int statusBarMinHeight, int maxShadeBottom, int notificationStackHeight,
-            float panelExpansion, int parentHeight, int keyguardStatusHeight,
-            int userSwitchHeight, int clockPreferredY, int userSwitchPreferredY,
-            boolean hasCustomClock, boolean hasVisibleNotifs, float dark, float emptyDragAmount,
-            boolean bypassEnabled, int unlockedStackScrollerPadding, boolean showLockIcon,
-            float qsExpansion, int cutoutTopInset) {
-        mMinTopMargin = statusBarMinHeight + (showLockIcon
-                ? mContainerTopPaddingWithLockIcon : mContainerTopPaddingWithoutLockIcon)
-                + userSwitchHeight;
+    public void setup(int keyguardStatusBarHeaderHeight, int maxShadeBottom,
+            int notificationStackHeight, float panelExpansion, int parentHeight,
+            int keyguardStatusHeight, int userSwitchHeight, int clockPreferredY,
+            int userSwitchPreferredY, boolean hasCustomClock, boolean hasVisibleNotifs, float dark,
+            float emptyDragAmount, boolean bypassEnabled, int unlockedStackScrollerPadding,
+            boolean showLockIcon, float qsExpansion, int cutoutTopInset) {
+        mMinTopMargin = keyguardStatusBarHeaderHeight + Math.max(showLockIcon
+                        ? mContainerTopPaddingWithLockIcon : mContainerTopPaddingWithoutLockIcon,
+                userSwitchHeight);
         mMaxShadeBottom = maxShadeBottom;
         mNotificationStackHeight = notificationStackHeight;
         mPanelExpansion = panelExpansion;
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 6940050..ae14fa9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -89,10 +89,8 @@
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.biometrics.AuthController;
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.classifier.Classifier;
 import com.android.systemui.classifier.FalsingCollector;
-import com.android.systemui.controls.dagger.ControlsComponent;
 import com.android.systemui.dagger.qualifiers.DisplayId;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.doze.DozeLog;
@@ -245,7 +243,6 @@
                 public void onLockScreenModeChanged(int mode) {
                     mLockScreenMode = mode;
                     mClockPositionAlgorithm.onLockScreenModeChanged(mode);
-                    mKeyguardBottomArea.onLockScreenModeChanged(mode);
                 }
 
                 @Override
@@ -287,21 +284,6 @@
                 }
     };
 
-    final KeyguardUserSwitcherController.KeyguardUserSwitcherListener
-            mKeyguardUserSwitcherListener =
-            new KeyguardUserSwitcherController.KeyguardUserSwitcherListener() {
-                @Override
-                public void onKeyguardUserSwitcherChanged(boolean open) {
-                    if (mKeyguardUserSwitcherController == null) {
-                        updateUserSwitcherVisibility(false);
-                    } else if (!mKeyguardUserSwitcherController.isSimpleUserSwitcher()) {
-                        updateUserSwitcherVisibility(open
-                                && mKeyguardStateController.isShowing()
-                                && !mKeyguardStateController.isKeyguardFadingAway());
-                    }
-                }
-            };
-
     private final LayoutInflater mLayoutInflater;
     private final PowerManager mPowerManager;
     private final AccessibilityManager mAccessibilityManager;
@@ -319,7 +301,6 @@
     private final QSDetailDisplayer mQSDetailDisplayer;
     private final FeatureFlags mFeatureFlags;
     private final ScrimController mScrimController;
-    private final ControlsComponent mControlsComponent;
 
     // 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
@@ -329,7 +310,6 @@
 
     private KeyguardAffordanceHelper mAffordanceHelper;
     private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController;
-    private boolean mKeyguardUserSwitcherIsShowing;
     private KeyguardUserSwitcherController mKeyguardUserSwitcherController;
     private KeyguardStatusBarView mKeyguardStatusBar;
     private ViewGroup mBigClockContainer;
@@ -374,6 +354,7 @@
     private ValueAnimator mQsExpansionAnimator;
     private FlingAnimationUtils mFlingAnimationUtils;
     private int mStatusBarMinHeight;
+    private int mStatusBarHeaderHeightKeyguard;
     private int mNotificationsHeaderCollideDistance;
     private float mEmptyDragAmount;
     private float mDownX;
@@ -535,7 +516,6 @@
     private NotificationShelfController mNotificationShelfController;
 
     private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
-    private BroadcastDispatcher mBroadcastDispatcher;
 
     private View.AccessibilityDelegate mAccessibilityDelegate = new View.AccessibilityDelegate() {
         @Override
@@ -593,9 +573,7 @@
             UserManager userManager,
             MediaDataManager mediaDataManager,
             AmbientState ambientState,
-            FeatureFlags featureFlags,
-            ControlsComponent controlsComponent,
-            BroadcastDispatcher broadcastDispatcher) {
+            FeatureFlags featureFlags) {
         super(view, falsingManager, dozeLog, keyguardStateController,
                 (SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
                 latencyTracker, flingAnimationUtilsBuilder.get(), statusBarTouchableRegionManager,
@@ -620,6 +598,7 @@
         mKeyguardQsUserSwitchEnabled =
                 mKeyguardUserSwitcherEnabled && mResources.getBoolean(
                         R.bool.config_keyguard_user_switch_opens_qs_details);
+        keyguardUpdateMonitor.setKeyguardQsUserSwitchEnabled(mKeyguardQsUserSwitchEnabled);
         mView.setWillNotDraw(!DEBUG);
         mLayoutInflater = layoutInflater;
         mFalsingManager = falsingManager;
@@ -637,7 +616,6 @@
         mScrimController = scrimController;
         mUserManager = userManager;
         mMediaDataManager = mediaDataManager;
-        mControlsComponent = controlsComponent;
         pulseExpansionHandler.setPulseExpandAbortListener(() -> {
             if (mQs != null) {
                 mQs.animateHeaderSlidingOut();
@@ -676,7 +654,6 @@
         mEntryManager = notificationEntryManager;
         mConversationNotificationManager = conversationNotificationManager;
         mAuthController = authController;
-        mBroadcastDispatcher = broadcastDispatcher;
 
         mView.setBackgroundColor(Color.TRANSPARENT);
         OnAttachStateChangeListener onAttachStateChangeListener = new OnAttachStateChangeListener();
@@ -772,6 +749,8 @@
                 .setMaxLengthSeconds(0.4f).build();
         mStatusBarMinHeight = mResources.getDimensionPixelSize(
                 com.android.internal.R.dimen.status_bar_height);
+        mStatusBarHeaderHeightKeyguard = mResources.getDimensionPixelSize(
+                R.dimen.status_bar_header_height_keyguard);
         mQsPeekHeight = mResources.getDimensionPixelSize(R.dimen.qs_peek_height);
         mNotificationsHeaderCollideDistance = mResources.getDimensionPixelSize(
                 R.dimen.header_notifications_collide_distance);
@@ -808,7 +787,6 @@
             // Try to close the switcher so that callbacks are triggered if necessary.
             // Otherwise, NPV can get into a state where some of the views are still hidden
             mKeyguardUserSwitcherController.closeSwitcherIfOpenAndNotSimple(false);
-            mKeyguardUserSwitcherController.removeCallback();
         }
 
         mKeyguardQsUserSwitchController = null;
@@ -828,7 +806,6 @@
                     mKeyguardUserSwitcherComponentFactory.build(keyguardUserSwitcherView);
             mKeyguardUserSwitcherController =
                     userSwitcherComponent.getKeyguardUserSwitcherController();
-            mKeyguardUserSwitcherController.setCallback(mKeyguardUserSwitcherListener);
             mKeyguardUserSwitcherController.init();
             mKeyguardStatusBar.setKeyguardUserSwitcherEnabled(true);
         } else {
@@ -986,7 +963,6 @@
         mKeyguardBottomArea.setAffordanceHelper(mAffordanceHelper);
         mKeyguardBottomArea.setStatusBar(mStatusBar);
         mKeyguardBottomArea.setUserSetupComplete(mUserSetupComplete);
-        mKeyguardBottomArea.setupControls(mControlsComponent, mBroadcastDispatcher);
     }
 
     private void updateMaxDisplayedNotifications(boolean recompute) {
@@ -1069,7 +1045,7 @@
             int totalHeight = mView.getHeight();
             int bottomPadding = Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding);
             int clockPreferredY = mKeyguardStatusViewController.getClockPreferredY(totalHeight);
-            int userSwitcherPreferredY = mStatusBarMinHeight;
+            int userSwitcherPreferredY = mStatusBarHeaderHeightKeyguard;
             boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled();
             final boolean hasVisibleNotifications = mNotificationStackScrollLayoutController
                     .getVisibleNotificationCount() != 0 || mMediaDataManager.hasActiveMedia();
@@ -1078,7 +1054,8 @@
                     ? mKeyguardQsUserSwitchController.getUserIconHeight()
                     : (mKeyguardUserSwitcherController != null
                             ? mKeyguardUserSwitcherController.getUserIconHeight() : 0);
-            mClockPositionAlgorithm.setup(mStatusBarMinHeight, totalHeight - bottomPadding,
+            mClockPositionAlgorithm.setup(mStatusBarHeaderHeightKeyguard,
+                    totalHeight - bottomPadding,
                     mNotificationStackScrollLayoutController.getIntrinsicContentHeight(),
                     getExpandedFraction(),
                     totalHeight,
@@ -3523,34 +3500,6 @@
         return false;
     }
 
-    private void updateUserSwitcherVisibility(boolean open) {
-        // Do not update if previously called with the same state.
-        if (mKeyguardUserSwitcherIsShowing == open) {
-            return;
-        }
-        mKeyguardUserSwitcherIsShowing = open;
-
-        if (open) {
-            animateKeyguardStatusBarOut();
-            mKeyguardStatusViewController.setKeyguardStatusViewVisibility(
-                    mBarState,
-                    true /* keyguardFadingAway */,
-                    true /* goingToFullShade */,
-                    mBarState);
-            setKeyguardBottomAreaVisibility(mBarState, true);
-            mNotificationContainerParent.setVisibility(View.GONE);
-        } else {
-            animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
-            mKeyguardStatusViewController.setKeyguardStatusViewVisibility(
-                    StatusBarState.KEYGUARD,
-                    false,
-                    false,
-                    StatusBarState.SHADE_LOCKED);
-            setKeyguardBottomAreaVisibility(mBarState, false);
-            mNotificationContainerParent.setVisibility(View.VISIBLE);
-        }
-    }
-
     private void updateDisabledUdfpsController() {
         final boolean udfpsEnrolled = mAuthController.getUdfpsRegion() != null
                 && mAuthController.isUdfpsEnrolled(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 55744f9..b6ed3e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -27,7 +27,6 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
-import android.annotation.Nullable;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.os.SystemClock;
@@ -1243,7 +1242,10 @@
                     mVelocityTracker.clear();
                     break;
             }
-            return false;
+
+            // Finally, if none of the above cases applies, ensure that touches do not get handled
+            // by the contents of a panel that is not showing (a bit of a hack to avoid b/178277858)
+            return (mView.getVisibility() != View.VISIBLE);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index b25fced..bf36435 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -78,7 +78,6 @@
 import android.metrics.LogMaker;
 import android.net.Uri;
 import android.os.AsyncTask;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -277,8 +276,7 @@
     public static final boolean DEBUG = false;
     public static final boolean SPEW = false;
     public static final boolean DUMPTRUCK = true; // extra dumpsys info
-    public static final boolean DEBUG_GESTURES = Build.IS_DEBUGGABLE; // TODO(b/178277858)
-    public static final boolean DEBUG_GESTURES_VERBOSE = true;
+    public static final boolean DEBUG_GESTURES = false;
     public static final boolean DEBUG_MEDIA_FAKE_ARTWORK = false;
     public static final boolean DEBUG_CAMERA_LIFT = false;
 
@@ -458,7 +456,9 @@
     private final DisplayMetrics mDisplayMetrics;
 
     // XXX: gesture research
-    private GestureRecorder mGestureRec = null;
+    private final GestureRecorder mGestureRec = DEBUG_GESTURES
+        ? new GestureRecorder("/sdcard/statusbar_gestures.dat")
+        : null;
 
     private final ScreenPinningRequest mScreenPinningRequest;
 
@@ -856,10 +856,6 @@
 
         mActivityIntentHelper = new ActivityIntentHelper(mContext);
         DateTimeView.setReceiverHandler(timeTickHandler);
-
-        if (DEBUG_GESTURES) {
-            mGestureRec = new GestureRecorder(mContext.getCacheDir() + "/statusbar_gestures.dat");
-        }
     }
 
     @Override
@@ -2271,7 +2267,7 @@
 
     public boolean interceptTouchEvent(MotionEvent event) {
         if (DEBUG_GESTURES) {
-            if (DEBUG_GESTURES_VERBOSE || event.getActionMasked() != MotionEvent.ACTION_MOVE) {
+            if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
                 EventLog.writeEvent(EventLogTags.SYSUI_STATUSBAR_TOUCH,
                         event.getActionMasked(), (int) event.getX(), (int) event.getY(),
                         mDisabled1, mDisabled2);
@@ -2696,6 +2692,10 @@
         return mDisplay.getRotation();
     }
 
+    int getDisplayId() {
+        return mDisplayId;
+    }
+
     public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
             boolean dismissShade, int flags) {
         startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade,
@@ -2721,7 +2721,7 @@
                     Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
             intent.addFlags(flags);
             int result = ActivityManager.START_CANCELED;
-            ActivityOptions options = new ActivityOptions(getActivityOptions(
+            ActivityOptions options = new ActivityOptions(getActivityOptions(mDisplayId,
                     null /* remoteAnimation */));
             options.setDisallowEnterPictureInPictureWhileLaunching(
                     disallowEnterPictureInPictureWhileLaunching);
@@ -4366,6 +4366,7 @@
         executeActionDismissingKeyguard(() -> {
             try {
                 intent.send(null, 0, null, null, null, null, getActivityOptions(
+                        mDisplayId,
                         mActivityLaunchAnimator.getLaunchAnimation(associatedView, isOccluded())));
             } catch (PendingIntent.CanceledException e) {
                 // the stack trace isn't very helpful here.
@@ -4387,15 +4388,38 @@
         mMainThreadHandler.post(runnable);
     }
 
-    public static Bundle getActivityOptions(@Nullable RemoteAnimationAdapter animationAdapter) {
+    /**
+     * Returns an ActivityOptions bundle created using the given parameters.
+     *
+     * @param displayId The ID of the display to launch the activity in. Typically this would be the
+     *                  display the status bar is on.
+     * @param animationAdapter The animation adapter used to start this activity, or {@code null}
+     *                         for the default animation.
+     */
+    public static Bundle getActivityOptions(int displayId,
+            @Nullable RemoteAnimationAdapter animationAdapter) {
         return getDefaultActivityOptions(animationAdapter).toBundle();
     }
 
-    public static Bundle getActivityOptions(@Nullable RemoteAnimationAdapter animationAdapter,
-            boolean isKeyguardShowing, long eventTime) {
+    /**
+     * Returns an ActivityOptions bundle created using the given parameters.
+     *
+     * @param displayId The ID of the display to launch the activity in. Typically this would be the
+     *                  display the status bar is on.
+     * @param animationAdapter The animation adapter used to start this activity, or {@code null}
+     *                         for the default animation.
+     * @param isKeyguardShowing Whether keyguard is currently showing.
+     * @param eventTime The event time in milliseconds since boot, not including sleep. See
+     *                  {@link ActivityOptions#setSourceInfo}.
+     */
+    public static Bundle getActivityOptions(int displayId,
+            @Nullable RemoteAnimationAdapter animationAdapter, boolean isKeyguardShowing,
+            long eventTime) {
         ActivityOptions options = getDefaultActivityOptions(animationAdapter);
         options.setSourceInfo(isKeyguardShowing ? ActivityOptions.SourceInfo.TYPE_LOCKSCREEN
                 : ActivityOptions.SourceInfo.TYPE_NOTIFICATION, eventTime);
+        options.setLaunchDisplayId(displayId);
+        options.setCallerDisplayId(displayId);
         return options.toBundle();
     }
 
@@ -4535,4 +4559,8 @@
     public void addExpansionChangedListener(@NonNull ExpansionChangedListener listener) {
         mExpansionChangedListeners.add(listener);
     }
+
+    public void removeExpansionChangedListener(@NonNull ExpansionChangedListener listener) {
+        mExpansionChangedListeners.remove(listener);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 598addc..34673f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -427,8 +427,13 @@
                                 intent.getCreatorPackage(), adapter);
             }
             long eventTime = row.getAndResetLastActionUpTime();
-            Bundle options = eventTime > 0 ? getActivityOptions(adapter,
-                    mKeyguardStateController.isShowing(), eventTime) : getActivityOptions(adapter);
+            Bundle options = eventTime > 0
+                    ? getActivityOptions(
+                            mStatusBar.getDisplayId(),
+                            adapter,
+                            mKeyguardStateController.isShowing(),
+                            eventTime)
+                    : getActivityOptions(mStatusBar.getDisplayId(), adapter);
             int launchResult = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
                     null, null, options);
             mMainThreadHandler.post(() -> {
@@ -450,6 +455,7 @@
                 int launchResult = TaskStackBuilder.create(mContext)
                         .addNextIntentWithParentStack(intent)
                         .startActivities(getActivityOptions(
+                                mStatusBar.getDisplayId(),
                                 mActivityLaunchAnimator.getLaunchAnimation(
                                         row, mStatusBar.isOccluded())),
                                 new UserHandle(UserHandle.getUserId(appUid)));
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 dacd941..9ee7b09 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -27,6 +27,8 @@
 import com.android.systemui.R;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
+import com.android.systemui.statusbar.policy.NetworkController.WifiIndicators;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl;
 import com.android.systemui.statusbar.policy.SecurityController;
 import com.android.systemui.tuner.TunerService;
@@ -143,24 +145,14 @@
     }
 
     @Override
-    public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
-            boolean activityIn, boolean activityOut, String description, boolean isTransient,
-            String statusLabel) {
+    public void setWifiIndicators(WifiIndicators indicators) {
         if (DEBUG) {
-            Log.d(TAG, "setWifiIndicators: "
-                    + "enabled = " + enabled + ","
-                    + "statusIcon = " + (statusIcon == null ? "" : statusIcon.toString()) + ","
-                    + "qsIcon = " + (qsIcon == null ? "" : qsIcon.toString()) + ","
-                    + "activityIn = " + activityIn + ","
-                    + "activityOut = " + activityOut + ","
-                    + "description = " + description + ","
-                    + "isTransient = " + isTransient + ","
-                    + "statusLabel = " + statusLabel);
+            Log.d(TAG, "setWifiIndicators: " + indicators);
         }
-        boolean visible = statusIcon.visible && !mHideWifi;
-        boolean in = activityIn && mActivityEnabled && visible;
-        boolean out = activityOut && mActivityEnabled && visible;
-        mIsWifiEnabled = enabled;
+        boolean visible = indicators.statusIcon.visible && !mHideWifi;
+        boolean in = indicators.activityIn && mActivityEnabled && visible;
+        boolean out = indicators.activityOut && mActivityEnabled && visible;
+        mIsWifiEnabled = indicators.enabled;
 
         WifiIconState newState = mWifiIconState.copy();
 
@@ -174,10 +166,10 @@
             newState.resId = R.drawable.ic_qs_no_internet_available;
         } else {
             newState.visible = visible;
-            newState.resId = statusIcon.icon;
+            newState.resId = indicators.statusIcon.icon;
             newState.activityIn = in;
             newState.activityOut = out;
-            newState.contentDescription = statusIcon.contentDescription;
+            newState.contentDescription = indicators.statusIcon.contentDescription;
             MobileIconState first = getFirstMobileState();
             newState.signalSpacerVisible = first != null && first.typeId != 0;
         }
@@ -225,44 +217,28 @@
     }
 
     @Override
-    public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
-            int qsType, boolean activityIn, boolean activityOut,
-            CharSequence typeContentDescription,
-            CharSequence typeContentDescriptionHtml, CharSequence description,
-            boolean isWide, int subId, boolean roaming, boolean showTriangle) {
+    public void setMobileDataIndicators(MobileDataIndicators indicators) {
         if (DEBUG) {
-            Log.d(TAG, "setMobileDataIndicators: "
-                    + "statusIcon = " + (statusIcon == null ? "" : statusIcon.toString()) + ","
-                    + "qsIcon = " + (qsIcon == null ? "" : qsIcon.toString()) + ","
-                    + "statusType = " + statusType + ","
-                    + "qsType = " + qsType + ","
-                    + "activityIn = " + activityIn + ","
-                    + "activityOut = " + activityOut + ","
-                    + "typeContentDescription = " + typeContentDescription + ","
-                    + "typeContentDescriptionHtml = " + typeContentDescriptionHtml + ","
-                    + "description = " + description + ","
-                    + "isWide = " + isWide + ","
-                    + "subId = " + subId + ","
-                    + "roaming = " + roaming + ","
-                    + "showTriangle = " + showTriangle);
+            Log.d(TAG, "setMobileDataIndicators: " + indicators);
         }
-        MobileIconState state = getState(subId);
+        MobileIconState state = getState(indicators.subId);
         if (state == null) {
             return;
         }
 
         // Visibility of the data type indicator changed
-        boolean typeChanged = statusType != state.typeId && (statusType == 0 || state.typeId == 0);
+        boolean typeChanged = indicators.statusType != state.typeId
+                && (indicators.statusType == 0 || state.typeId == 0);
 
-        state.visible = statusIcon.visible && !mHideMobile;
-        state.strengthId = statusIcon.icon;
-        state.typeId = statusType;
-        state.contentDescription = statusIcon.contentDescription;
-        state.typeContentDescription = typeContentDescription;
-        state.showTriangle = showTriangle;
-        state.roaming = roaming;
-        state.activityIn = activityIn && mActivityEnabled;
-        state.activityOut = activityOut && mActivityEnabled;
+        state.visible = indicators.statusIcon.visible && !mHideMobile;
+        state.strengthId = indicators.statusIcon.icon;
+        state.typeId = indicators.statusType;
+        state.contentDescription = indicators.statusIcon.contentDescription;
+        state.typeContentDescription = indicators.typeContentDescription;
+        state.showTriangle = indicators.showTriangle;
+        state.roaming = indicators.roaming;
+        state.activityIn = indicators.activityIn && mActivityEnabled;
+        state.activityOut = indicators.activityOut && mActivityEnabled;
 
         if (DEBUG) {
             Log.d(TAG, "MobileIconStates: "
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
index 528c0cb..b96cb5e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
@@ -23,7 +23,9 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import com.android.systemui.statusbar.policy.NetworkController.WifiIndicators;
 
 import java.io.PrintWriter;
 import java.text.SimpleDateFormat;
@@ -119,63 +121,29 @@
     }
 
     @Override
-    public void setWifiIndicators(final boolean enabled, final IconState statusIcon,
-            final IconState qsIcon, final boolean activityIn, final boolean activityOut,
-            final String description, boolean isTransient, String secondaryLabel) {
+    public void setWifiIndicators(final WifiIndicators indicators) {
         String log = new StringBuilder()
                 .append(SSDF.format(System.currentTimeMillis())).append(",")
-                .append("setWifiIndicators: ")
-                .append("enabled=").append(enabled).append(",")
-                .append("statusIcon=").append(statusIcon).append(",")
-                .append("qsIcon=").append(qsIcon).append(",")
-                .append("activityIn=").append(activityIn).append(",")
-                .append("activityOut=").append(activityOut).append(",")
-                .append("description=").append(description).append(",")
-                .append("isTransient=").append(isTransient).append(",")
-                .append("secondaryLabel=").append(secondaryLabel)
+                .append(indicators)
                 .toString();
         recordLastCallback(log);
         post(() -> {
             for (SignalCallback callback : mSignalCallbacks) {
-                callback.setWifiIndicators(enabled, statusIcon, qsIcon, activityIn, activityOut,
-                        description, isTransient, secondaryLabel);
+                callback.setWifiIndicators(indicators);
             }
         });
-
-
     }
 
     @Override
-    public void setMobileDataIndicators(final IconState statusIcon, final IconState qsIcon,
-            final int statusType, final int qsType, final boolean activityIn,
-            final boolean activityOut, final CharSequence typeContentDescription,
-            CharSequence typeContentDescriptionHtml, final CharSequence description,
-            final boolean isWide, final int subId, boolean roaming, boolean showTriangle) {
+    public void setMobileDataIndicators(final MobileDataIndicators indicators) {
         String log = new StringBuilder()
                 .append(SSDF.format(System.currentTimeMillis())).append(",")
-                .append("setMobileDataIndicators: ")
-                .append("statusIcon=").append(statusIcon).append(",")
-                .append("qsIcon=").append(qsIcon).append(",")
-                .append("statusType=").append(statusType).append(",")
-                .append("qsType=").append(qsType).append(",")
-                .append("activityIn=").append(activityIn).append(",")
-                .append("activityOut=").append(activityOut).append(",")
-                .append("typeContentDescription=").append(typeContentDescription).append(",")
-                .append("typeContentDescriptionHtml=").append(typeContentDescriptionHtml)
-                .append(",")
-                .append("description=").append(description).append(",")
-                .append("isWide=").append(isWide).append(",")
-                .append("subId=").append(subId).append(",")
-                .append("roaming=").append(roaming).append(",")
-                .append("showTriangle=").append(showTriangle)
+                .append(indicators)
                 .toString();
         recordLastCallback(log);
         post(() -> {
             for (SignalCallback signalCluster : mSignalCallbacks) {
-                signalCluster.setMobileDataIndicators(statusIcon, qsIcon, statusType, qsType,
-                        activityIn, activityOut, typeContentDescription,
-                        typeContentDescriptionHtml, description, isWide, subId, roaming,
-                        showTriangle);
+                signalCluster.setMobileDataIndicators(indicators);
             }
         });
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java
index a76d08a..7f935d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyController.java
@@ -16,17 +16,17 @@
 
 package com.android.systemui.statusbar.policy;
 
-import android.hardware.SensorPrivacyManager.IndividualSensor;
+import android.hardware.SensorPrivacyManager.Sensors.Sensor;
 
 public interface IndividualSensorPrivacyController extends
         CallbackController<IndividualSensorPrivacyController.Callback> {
     void init();
 
-    boolean isSensorBlocked(@IndividualSensor int sensor);
+    boolean isSensorBlocked(@Sensor int sensor);
 
-    void setSensorBlocked(@IndividualSensor int sensor, boolean blocked);
+    void setSensorBlocked(@Sensor int sensor, boolean blocked);
 
     interface Callback {
-        void onSensorBlockedChanged(@IndividualSensor int sensor, boolean blocked);
+        void onSensorBlockedChanged(@Sensor int sensor, boolean blocked);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java
index 32d15ed..295df05 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java
@@ -16,11 +16,11 @@
 
 package com.android.systemui.statusbar.policy;
 
-import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_CAMERA;
-import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE;
+import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
+import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE;
 
 import android.hardware.SensorPrivacyManager;
-import android.hardware.SensorPrivacyManager.IndividualSensor;
+import android.hardware.SensorPrivacyManager.Sensors.Sensor;
 import android.util.ArraySet;
 import android.util.SparseBooleanArray;
 
@@ -30,8 +30,7 @@
 
 public class IndividualSensorPrivacyControllerImpl implements IndividualSensorPrivacyController {
 
-    private static final int[] SENSORS = new int[] {INDIVIDUAL_SENSOR_CAMERA,
-            INDIVIDUAL_SENSOR_MICROPHONE};
+    private static final int[] SENSORS = new int[] {CAMERA, MICROPHONE};
 
     private final @NonNull SensorPrivacyManager mSensorPrivacyManager;
     private final SparseBooleanArray mState = new SparseBooleanArray();
@@ -48,18 +47,18 @@
             mSensorPrivacyManager.addSensorPrivacyListener(sensor,
                     (enabled) -> onSensorPrivacyChanged(sensor, enabled));
 
-            mState.put(sensor, mSensorPrivacyManager.isIndividualSensorPrivacyEnabled(sensor));
+            mState.put(sensor, mSensorPrivacyManager.isSensorPrivacyEnabled(sensor));
         }
     }
 
     @Override
-    public boolean isSensorBlocked(@IndividualSensor int sensor) {
+    public boolean isSensorBlocked(@Sensor int sensor) {
         return mState.get(sensor, false);
     }
 
     @Override
-    public void setSensorBlocked(@IndividualSensor int sensor, boolean blocked) {
-        mSensorPrivacyManager.setIndividualSensorPrivacyForProfileGroup(sensor, blocked);
+    public void setSensorBlocked(@Sensor int sensor, boolean blocked) {
+        mSensorPrivacyManager.setSensorPrivacyForProfileGroup(sensor, blocked);
     }
 
     @Override
@@ -72,7 +71,7 @@
         mCallbacks.remove(listener);
     }
 
-    private void onSensorPrivacyChanged(@IndividualSensor int sensor, boolean blocked) {
+    private void onSensorPrivacyChanged(@Sensor int sensor, boolean blocked) {
         mState.put(sensor, blocked);
 
         for (Callback callback : mCallbacks) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/InflatedSmartReplyViewHolder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/InflatedSmartReplyViewHolder.kt
index 4f69cd6..4e5c461 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/InflatedSmartReplyViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/InflatedSmartReplyViewHolder.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 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.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
index b76e451..8845a05 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
@@ -19,9 +19,13 @@
 import static com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_DISABLED_ALPHA;
 import static com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_ENABLED_ALPHA;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.content.res.Resources;
 import android.database.DataSetObserver;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
 import android.os.UserHandle;
@@ -50,7 +54,6 @@
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.ViewController;
 
-import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 
 import javax.inject.Inject;
@@ -73,9 +76,10 @@
     private final KeyguardUserAdapter mAdapter;
     private final KeyguardStateController mKeyguardStateController;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
-    private WeakReference<KeyguardUserSwitcherListener> mKeyguardUserSwitcherCallback;
     protected final SysuiStatusBarStateController mStatusBarStateController;
     private final KeyguardVisibilityHelper mKeyguardVisibilityHelper;
+    private ObjectAnimator mBgAnimator;
+    private final KeyguardUserSwitcherScrim mBackground;
 
     // Child views of KeyguardUserSwitcherView
     private KeyguardUserSwitcherListView mListView;
@@ -171,6 +175,7 @@
                 mUserSwitcherController, this);
         mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView,
                 keyguardStateController, dozeParameters);
+        mBackground = new KeyguardUserSwitcherScrim(context);
     }
 
     @Override
@@ -204,6 +209,9 @@
         mKeyguardUpdateMonitor.registerCallback(mInfoCallback);
         mStatusBarStateController.addCallback(mStatusBarStateListener);
         mScreenLifecycle.addObserver(mScreenObserver);
+        mView.addOnLayoutChangeListener(mBackground);
+        mView.setBackground(mBackground);
+        mBackground.setAlpha(0);
     }
 
     @Override
@@ -217,6 +225,9 @@
         mKeyguardUpdateMonitor.removeCallback(mInfoCallback);
         mStatusBarStateController.removeCallback(mStatusBarStateListener);
         mScreenLifecycle.removeObserver(mScreenObserver);
+        mView.removeOnLayoutChangeListener(mBackground);
+        mView.setBackground(null);
+        mBackground.setAlpha(0);
     }
 
     /**
@@ -338,6 +349,13 @@
                 animate);
         PropertyAnimator.setProperty(mListView, AnimatableProperty.TRANSLATION_X, -Math.abs(x),
                 ANIMATION_PROPERTIES, animate);
+
+        Rect r = new Rect();
+        mListView.getDrawingRect(r);
+        mView.offsetDescendantRectToMyCoords(mListView, r);
+        mBackground.setGradientCenter(
+                (int) (mListView.getTranslationX() + r.left + r.width() / 2),
+                (int) (mListView.getTranslationY() + r.top + r.height() / 2));
     }
 
     /**
@@ -372,49 +390,52 @@
     }
 
     /**
-     * Remove the callback if it exists.
-     */
-    public void removeCallback() {
-        if (DEBUG) Log.d(TAG, "removeCallback");
-        mKeyguardUserSwitcherCallback = null;
-    }
-
-    /**
-     * Register to receive notifications about keyguard user switcher state
-     * (see {@link KeyguardUserSwitcherListener}.
-     *
-     * Only one callback can be used at a time.
-     *
-     * @param callback The callback to register
-     */
-    public void setCallback(KeyguardUserSwitcherListener callback) {
-        if (DEBUG) Log.d(TAG, "setCallback");
-        mKeyguardUserSwitcherCallback = new WeakReference<>(callback);
-    }
-
-    /**
-     * If user switcher state changes, notifies all {@link KeyguardUserSwitcherListener}.
-     * Switcher state is updatd before animations finish.
+     * NOTE: switcher state is updated before animations finish.
      *
      * @param animate true to animate transition. The user switcher state (i.e.
      *                {@link #isUserSwitcherOpen()}) is updated before animation is finished.
      */
     private void setUserSwitcherOpened(boolean open, boolean animate) {
-        boolean wasOpen = mUserSwitcherOpen;
         if (DEBUG) {
-            Log.d(TAG, String.format("setUserSwitcherOpened: %b -> %b (animate=%b)", wasOpen,
-                    open, animate));
+            Log.d(TAG,
+                    String.format("setUserSwitcherOpened: %b -> %b (animate=%b)",
+                            mUserSwitcherOpen, open, animate));
         }
         mUserSwitcherOpen = open;
-        if (mUserSwitcherOpen != wasOpen) {
-            notifyUserSwitcherStateChanged();
-        }
         updateVisibilities(animate);
     }
 
     private void updateVisibilities(boolean animate) {
         if (DEBUG) Log.d(TAG, String.format("updateVisibilities: animate=%b", animate));
         mEndGuestButton.animate().cancel();
+        if (mBgAnimator != null) {
+            mBgAnimator.cancel();
+        }
+
+        if (mUserSwitcherOpen) {
+            mBgAnimator = ObjectAnimator.ofInt(mBackground, "alpha", 0, 255);
+            mBgAnimator.setDuration(400);
+            mBgAnimator.setInterpolator(Interpolators.ALPHA_IN);
+            mBgAnimator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mBgAnimator = null;
+                }
+            });
+            mBgAnimator.start();
+        } else {
+            mBgAnimator = ObjectAnimator.ofInt(mBackground, "alpha", 255, 0);
+            mBgAnimator.setDuration(400);
+            mBgAnimator.setInterpolator(Interpolators.ALPHA_OUT);
+            mBgAnimator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mBgAnimator = null;
+                }
+            });
+            mBgAnimator.start();
+        }
+
         if (mUserSwitcherOpen && mCurrentUserIsGuest) {
             // Show the "End guest session" button
             mEndGuestButton.setVisibility(View.VISIBLE);
@@ -459,34 +480,6 @@
         return mUserSwitcherOpen;
     }
 
-    private void notifyUserSwitcherStateChanged() {
-        if (DEBUG) {
-            Log.d(TAG, String.format("notifyUserSwitcherStateChanged: mUserSwitcherOpen=%b",
-                    mUserSwitcherOpen));
-        }
-        if (mKeyguardUserSwitcherCallback != null) {
-            KeyguardUserSwitcherListener cb = mKeyguardUserSwitcherCallback.get();
-            if (cb != null) {
-                cb.onKeyguardUserSwitcherChanged(mUserSwitcherOpen);
-            }
-        }
-    }
-
-    /**
-     * Callback for keyguard user switcher state information
-     */
-    public interface KeyguardUserSwitcherListener {
-
-        /**
-         * Called when the keyguard enters or leaves user switcher mode. This will be called
-         * before the animations are finished.
-         *
-         * @param open if true, keyguard is showing the user switcher or transitioning from/to user
-         *             switcher mode.
-         */
-        void onKeyguardUserSwitcherChanged(boolean open);
-    }
-
     static class KeyguardUserAdapter extends
             UserSwitcherController.BaseUserAdapter implements View.OnClickListener {
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java
index 49f5bcd..1d9d33d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java
@@ -26,7 +26,6 @@
 import android.graphics.Rect;
 import android.graphics.Shader;
 import android.graphics.drawable.Drawable;
-import android.util.LayoutDirection;
 import android.view.View;
 
 import com.android.systemui.R;
@@ -38,13 +37,14 @@
         implements View.OnLayoutChangeListener {
 
     private static final float OUTER_EXTENT = 2.5f;
-    private static final float INNER_EXTENT = 0.75f;
+    private static final float INNER_EXTENT = 0.25f;
 
     private int mDarkColor;
-    private int mTop;
     private int mAlpha = 255;
     private Paint mRadialGradientPaint = new Paint();
-    private int mLayoutWidth;
+    private int mCircleX;
+    private int mCircleY;
+    private int mSize;
 
     public KeyguardUserSwitcherScrim(Context context) {
         mDarkColor = context.getColor(
@@ -53,14 +53,11 @@
 
     @Override
     public void draw(Canvas canvas) {
-        boolean isLtr = getLayoutDirection() == LayoutDirection.LTR;
+        if (mAlpha == 0) {
+            return;
+        }
         Rect bounds = getBounds();
-        float width = bounds.width() * OUTER_EXTENT;
-        float height = (mTop + bounds.height()) * OUTER_EXTENT;
-        canvas.translate(0, -mTop);
-        canvas.scale(1, height / width);
-        canvas.drawRect(isLtr ? bounds.right - width : 0, 0,
-                isLtr ? bounds.right : bounds.left + width, width, mRadialGradientPaint);
+        canvas.drawRect(bounds.left, bounds.top, bounds.right, bounds.bottom, mRadialGradientPaint);
     }
 
     @Override
@@ -88,24 +85,36 @@
     public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
             int oldTop, int oldRight, int oldBottom) {
         if (left != oldLeft || top != oldTop || right != oldRight || bottom != oldBottom) {
-            mLayoutWidth = right - left;
-            mTop = top;
+            int width = right - left;
+            int height = bottom - top;
+            mSize = Math.max(width, height);
             updatePaint();
         }
     }
 
     private void updatePaint() {
-        if (mLayoutWidth == 0) {
+        if (mSize == 0) {
             return;
         }
-        float radius = mLayoutWidth * OUTER_EXTENT;
-        boolean isLtr = getLayoutDirection() == LayoutDirection.LTR;
+        float outerRadius = mSize * OUTER_EXTENT;
         mRadialGradientPaint.setShader(
-                new RadialGradient(isLtr ? mLayoutWidth : 0, 0, radius,
+                new RadialGradient(mCircleX, mCircleY, outerRadius,
                         new int[] { Color.argb(
                                         (int) (Color.alpha(mDarkColor) * mAlpha / 255f), 0, 0, 0),
                                 Color.TRANSPARENT },
-                        new float[] { Math.max(0f, mLayoutWidth * INNER_EXTENT / radius), 1f },
+                        new float[] { Math.max(0f, INNER_EXTENT / OUTER_EXTENT), 1f },
                         Shader.TileMode.CLAMP));
     }
+
+    /**
+     * Sets the center of the radial gradient used as a background
+     *
+     * @param x
+     * @param y
+     */
+    public void setGradientCenter(int x, int y) {
+        mCircleX = x;
+        mCircleY = y;
+        updatePaint();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 1ab7652..044f52f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -59,6 +59,7 @@
 import com.android.settingslib.net.SignalStrengthUtil;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
 
 import java.io.PrintWriter;
@@ -382,8 +383,15 @@
             int qsTypeIcon = 0;
             IconState qsIcon = null;
             CharSequence description = null;
+            // Mobile icon will only be shown in the statusbar in 2 scenarios
+            // 1. Mobile is the default network, and it is validated
+            // 2. Mobile is the default network, it is not validated and there is no other
+            // non-Carrier WiFi networks available.
+            boolean maybeShowIcons = (mCurrentState.inetCondition == 1)
+                    || (mCurrentState.inetCondition == 0
+                            && !mNetworkController.isNonCarrierWifiNetworkAvailable());
             // Only send data sim callbacks to QS.
-            if (mCurrentState.dataSim && mCurrentState.isDefault) {
+            if (mCurrentState.dataSim && mCurrentState.isDefault && maybeShowIcons) {
                 qsTypeIcon =
                         (showDataIcon || mConfig.alwaysShowDataRatIcon) ? icons.qsDataType : 0;
                 qsIcon = new IconState(mCurrentState.enabled
@@ -396,16 +404,18 @@
             boolean activityOut = mCurrentState.dataConnected
                     && !mCurrentState.carrierNetworkChangeMode
                     && mCurrentState.activityOut;
-            showDataIcon &= mCurrentState.dataSim && mCurrentState.isDefault;
+            showDataIcon &= mCurrentState.dataSim && mCurrentState.isDefault && maybeShowIcons;
             boolean showTriangle = showDataIcon && !mCurrentState.airplaneMode;
             int typeIcon = (showDataIcon || mConfig.alwaysShowDataRatIcon) ? icons.dataType : 0;
             showDataIcon |= mCurrentState.roaming;
             IconState statusIcon = new IconState(showDataIcon && !mCurrentState.airplaneMode,
                     getCurrentIconId(), contentDescription);
-            callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
+            MobileDataIndicators mobileDataIndicators = new MobileDataIndicators(
+                    statusIcon, qsIcon, typeIcon, qsTypeIcon,
                     activityIn, activityOut, dataContentDescription, dataContentDescriptionHtml,
                     description, icons.isWide, mSubscriptionInfo.getSubscriptionId(),
                     mCurrentState.roaming, showTriangle);
+            callback.setMobileDataIndicators(mobileDataIndicators);
         } else {
             boolean showDataIcon = mCurrentState.dataConnected || dataDisabled;
             IconState statusIcon = new IconState(
@@ -432,10 +442,12 @@
             showDataIcon &= mCurrentState.isDefault || dataDisabled;
             int typeIcon = (showDataIcon || mConfig.alwaysShowDataRatIcon) ? icons.dataType : 0;
             boolean showTriangle = mCurrentState.enabled && !mCurrentState.airplaneMode;
-            callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
+            MobileDataIndicators mobileDataIndicators = new MobileDataIndicators(
+                    statusIcon, qsIcon, typeIcon, qsTypeIcon,
                     activityIn, activityOut, dataContentDescription, dataContentDescriptionHtml,
                     description, icons.isWide, mSubscriptionInfo.getSubscriptionId(),
                     mCurrentState.roaming, showTriangle);
+            callback.setMobileDataIndicators(mobileDataIndicators);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 0a9fead..ef2ca98 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -46,34 +46,117 @@
 
     boolean isRadioOn();
 
+    /**
+     * Wrapper class for all the WiFi signals used for WiFi indicators.
+     */
+    final class WifiIndicators {
+        public boolean enabled;
+        public IconState statusIcon;
+        public IconState qsIcon;
+        public boolean activityIn;
+        public boolean activityOut;
+        public String description;
+        public boolean isTransient;
+        public String statusLabel;
+
+        public WifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
+                boolean activityIn, boolean activityOut, String description,
+                boolean isTransient, String statusLabel) {
+            this.enabled = enabled;
+            this.statusIcon = statusIcon;
+            this.qsIcon = qsIcon;
+            this.activityIn = activityIn;
+            this.activityOut = activityOut;
+            this.description = description;
+            this.isTransient = isTransient;
+            this.statusLabel = statusLabel;
+        }
+
+        @Override
+        public String toString() {
+            return new StringBuilder("WifiIndicators[")
+                .append("enabled=").append(enabled)
+                .append(",statusIcon=").append(statusIcon == null ? "" : statusIcon.toString())
+                .append(",qsIcon=").append(qsIcon == null ? "" : qsIcon.toString())
+                .append(",activityIn=").append(activityIn)
+                .append(",activityOut=").append(activityOut)
+                .append(",description=").append(description)
+                .append(",isTransient=").append(isTransient)
+                .append(",statusLabel=").append(statusLabel)
+                .append(']').toString();
+        }
+    }
+
+    /**
+     * Wrapper class for all the mobile signals used for mobile data indicators.
+     */
+    final class MobileDataIndicators {
+        public IconState statusIcon;
+        public IconState qsIcon;
+        public int statusType;
+        public int qsType;
+        public boolean activityIn;
+        public boolean activityOut;
+        public CharSequence typeContentDescription;
+        public CharSequence typeContentDescriptionHtml;
+        public CharSequence description;
+        public boolean isWide;
+        public int subId;
+        public boolean roaming;
+        public boolean showTriangle;
+
+        public MobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
+                int qsType, boolean activityIn, boolean activityOut,
+                CharSequence typeContentDescription, CharSequence typeContentDescriptionHtml,
+                CharSequence description, boolean isWide, int subId, boolean roaming,
+                boolean showTriangle) {
+            this.statusIcon = statusIcon;
+            this.qsIcon = qsIcon;
+            this.statusType = statusType;
+            this.qsType = qsType;
+            this.activityIn = activityIn;
+            this.activityOut = activityOut;
+            this.typeContentDescription = typeContentDescription;
+            this.typeContentDescriptionHtml = typeContentDescriptionHtml;
+            this.description = description;
+            this.isWide = isWide;
+            this.subId = subId;
+            this.roaming = roaming;
+            this.showTriangle = showTriangle;
+        }
+
+        @Override
+        public String toString() {
+            return new StringBuilder("MobileDataIndicators[")
+                .append("statusIcon=").append(statusIcon == null ? "" :  statusIcon.toString())
+                .append(",qsIcon=").append(qsIcon == null ? "" : qsIcon.toString())
+                .append(",statusType=").append(statusType)
+                .append(",qsType=").append(qsType)
+                .append(",activityIn=").append(activityIn)
+                .append(",activityOut=").append(activityOut)
+                .append(",typeContentDescription=").append(typeContentDescription)
+                .append(",typeContentDescriptionHtml=").append(typeContentDescriptionHtml)
+                .append(",description=").append(description)
+                .append(",isWide=").append(isWide)
+                .append(",subId=").append(subId)
+                .append(",roaming=").append(roaming)
+                .append(",showTriangle=").append(showTriangle)
+                .append(']').toString();
+        }
+    }
+
     public interface SignalCallback {
-        default void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
-                boolean activityIn, boolean activityOut, String description, boolean isTransient,
-                String statusLabel) {}
+        /**
+         * Callback for listeners to be able to update the state of any UI tracking connectivity of
+         * WiFi networks.
+         */
+        default void setWifiIndicators(WifiIndicators wifiIndicators) {}
 
         /**
          * Callback for listeners to be able to update the state of any UI tracking connectivity
-         * @param statusIcon the icon that should be shown in the status bar
-         * @param qsIcon the icon to show in Quick Settings
-         * @param statusType the resId of the data type icon (e.g. LTE) to show in the status bar
-         * @param qsType similar to above, the resId of the data type icon to show in Quick Settings
-         * @param activityIn indicates whether there is inbound activity
-         * @param activityOut indicates outbound activity
-         * @param typeContentDescription the contentDescription of the data type
-         * @param typeContentDescriptionHtml the (possibly HTML-styled) contentDescription of the
-         *                                   data type. Suitable for display
-         * @param description description of the network (usually just the network name)
-         * @param isWide //TODO: unused?
-         * @param subId subscription ID for which to update the UI
-         * @param roaming indicates roaming
-         * @param showTriangle whether to show the mobile triangle the in status bar
+         * of Mobile networks.
          */
-        default void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
-                int qsType, boolean activityIn, boolean activityOut,
-                CharSequence typeContentDescription,
-                CharSequence typeContentDescriptionHtml, CharSequence description,
-                boolean isWide, int subId, boolean roaming, boolean showTriangle) {
-        }
+        default void setMobileDataIndicators(MobileDataIndicators mobileDataIndicators) {}
 
         default void setSubs(List<SubscriptionInfo> subs) {}
 
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 9f92142..fbdaf9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -165,7 +165,7 @@
     private int mCurrentUserId;
 
     private OnSubscriptionsChangedListener mSubscriptionListener;
-
+    private NetworkCapabilities mLastDefaultNetworkCapabilities;
     // Handler that all broadcasts are received on.
     private final Handler mReceiverHandler;
     // Handler that all callbacks are made on.
@@ -315,6 +315,7 @@
             public void onLost(Network network) {
                 mLastNetwork = null;
                 mLastNetworkCapabilities = null;
+                mLastDefaultNetworkCapabilities = null;
                 String callback = new StringBuilder()
                         .append(SSDF.format(System.currentTimeMillis())).append(",")
                         .append("onLost: ")
@@ -341,6 +342,7 @@
                 }
                 mLastNetwork = network;
                 mLastNetworkCapabilities = networkCapabilities;
+                mLastDefaultNetworkCapabilities = networkCapabilities;
                 String callback = new StringBuilder()
                         .append(SSDF.format(System.currentTimeMillis())).append(",")
                         .append("onCapabilitiesChanged: ")
@@ -545,6 +547,10 @@
         return mWifiSignalController.isCarrierMergedWifi(subId);
     }
 
+    boolean isNonCarrierWifiNetworkAvailable() {
+        return !mNoNetworksAvailable;
+    }
+
     boolean isEthernetDefault() {
         return mConnectedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET);
     }
@@ -906,6 +912,11 @@
         return true;
     }
 
+    @VisibleForTesting
+    void setNoNetworksAvailable(boolean noNetworksAvailable) {
+        mNoNetworksAvailable = noNetworksAvailable;
+    }
+
     private void updateAirplaneMode(boolean force) {
         boolean airplaneMode = (Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.AIRPLANE_MODE_ON, 0) == 1);
@@ -959,18 +970,17 @@
     private void updateConnectivity() {
         mConnectedTransports.clear();
         mValidatedTransports.clear();
-        for (NetworkCapabilities nc :
-                mConnectivityManager.getDefaultNetworkCapabilitiesForUser(mCurrentUserId)) {
-            for (int transportType : nc.getTransportTypes()) {
+        if (mLastDefaultNetworkCapabilities != null) {
+            for (int transportType : mLastDefaultNetworkCapabilities.getTransportTypes()) {
                 if (transportType == NetworkCapabilities.TRANSPORT_CELLULAR
-                        && Utils.tryGetWifiInfoForVcn(nc) != null) {
+                        && Utils.tryGetWifiInfoForVcn(mLastDefaultNetworkCapabilities) != null) {
                     mConnectedTransports.set(NetworkCapabilities.TRANSPORT_WIFI);
-                    if (nc.hasCapability(NET_CAPABILITY_VALIDATED)) {
+                    if (mLastDefaultNetworkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
                         mValidatedTransports.set(NetworkCapabilities.TRANSPORT_WIFI);
                     }
                 } else {
                     mConnectedTransports.set(transportType);
-                    if (nc.hasCapability(NET_CAPABILITY_VALIDATED)) {
+                    if (mLastDefaultNetworkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
                         mValidatedTransports.set(transportType);
                     }
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index 16998d7..b9b62b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -38,7 +38,9 @@
 import com.android.settingslib.wifi.WifiStatusTracker;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import com.android.systemui.statusbar.policy.NetworkController.WifiIndicators;
 
 import java.io.PrintWriter;
 import java.util.Objects;
@@ -104,27 +106,43 @@
         if (mCurrentState.inetCondition == 0) {
             contentDescription += ("," + mContext.getString(R.string.data_connection_no_internet));
         }
-        IconState statusIcon = new IconState(wifiVisible, getCurrentIconId(), contentDescription);
         if (mProviderModel) {
+            // WiFi icon will only be shown in the statusbar in 2 scenarios
+            // 1. WiFi is the default network, and it is validated
+            // 2. WiFi is the default network, it is not validated and there is no other
+            // non-Carrier WiFi networks available.
+            boolean maybeShowIcons = (mCurrentState.inetCondition == 1)
+                    || (mCurrentState.inetCondition == 0
+                            && !mNetworkController.isNonCarrierWifiNetworkAvailable());
+            IconState statusIcon = new IconState(
+                    wifiVisible && maybeShowIcons, getCurrentIconId(), contentDescription);
             IconState qsIcon = null;
-            if (mCurrentState.isDefault || (!mNetworkController.isRadioOn()
+            if ((mCurrentState.isDefault && maybeShowIcons) || (!mNetworkController.isRadioOn()
                     && !mNetworkController.isEthernetDefault())) {
                 qsIcon = new IconState(mCurrentState.connected,
                         mWifiTracker.isCaptivePortal ? R.drawable.ic_qs_wifi_disconnected
                                 : getQsCurrentIconId(), contentDescription);
             }
-            callback.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon,
+            WifiIndicators wifiIndicators = new WifiIndicators(
+                    mCurrentState.enabled, statusIcon, qsIcon,
                     ssidPresent && mCurrentState.activityIn,
                     ssidPresent && mCurrentState.activityOut,
-                    wifiDesc, mCurrentState.isTransient, mCurrentState.statusLabel);
+                    wifiDesc, mCurrentState.isTransient, mCurrentState.statusLabel
+            );
+            callback.setWifiIndicators(wifiIndicators);
         } else {
+            IconState statusIcon = new IconState(
+                    wifiVisible, getCurrentIconId(), contentDescription);
             IconState qsIcon = new IconState(mCurrentState.connected,
                     mWifiTracker.isCaptivePortal ? R.drawable.ic_qs_wifi_disconnected
                             : getQsCurrentIconId(), contentDescription);
-            callback.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon,
+            WifiIndicators wifiIndicators = new WifiIndicators(
+                    mCurrentState.enabled, statusIcon, qsIcon,
                     ssidPresent && mCurrentState.activityIn,
                     ssidPresent && mCurrentState.activityOut,
-                    wifiDesc, mCurrentState.isTransient, mCurrentState.statusLabel);
+                    wifiDesc, mCurrentState.isTransient, mCurrentState.statusLabel
+            );
+            callback.setWifiIndicators(wifiIndicators);
         }
     }
 
@@ -138,21 +156,34 @@
         if (mCurrentState.inetCondition == 0) {
             dataContentDescription = mContext.getString(R.string.data_connection_no_internet);
         }
-        boolean qsVisible = mCurrentState.enabled
-                && (mCurrentState.connected && mCurrentState.inetCondition == 1);
-
+        // Mobile icon will only be shown in the statusbar in 2 scenarios
+        // 1. Mobile is the default network, and it is validated
+        // 2. Mobile is the default network, it is not validated and there is no other
+        // non-Carrier WiFi networks available.
+        boolean maybeShowIcons = (mCurrentState.inetCondition == 1)
+                || (mCurrentState.inetCondition == 0
+                        && !mNetworkController.isNonCarrierWifiNetworkAvailable());
+        boolean sbVisible = mCurrentState.enabled && mCurrentState.connected
+                && maybeShowIcons && mCurrentState.isDefault;
         IconState statusIcon =
-                new IconState(qsVisible, getCurrentIconIdForCarrierWifi(), contentDescription);
-        int qsTypeIcon = mCurrentState.connected ? icons.qsDataType : 0;
-        int typeIcon = mCurrentState.connected ? icons.dataType : 0;
-        IconState qsIcon = new IconState(
-                mCurrentState.connected, getQsCurrentIconIdForCarrierWifi(), contentDescription);
+                new IconState(sbVisible, getCurrentIconIdForCarrierWifi(), contentDescription);
+        int typeIcon = sbVisible ? icons.dataType : 0;
+        int qsTypeIcon = 0;
+        IconState qsIcon = null;
+        if (sbVisible) {
+            qsTypeIcon = icons.qsDataType;
+            qsIcon = new IconState(mCurrentState.connected, getQsCurrentIconIdForCarrierWifi(),
+                    contentDescription);
+        }
         CharSequence description =
                 mNetworkController.getNetworkNameForCarrierWiFi(mCurrentState.subId);
-        callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
+        MobileDataIndicators mobileDataIndicators = new MobileDataIndicators(
+                statusIcon, qsIcon, typeIcon, qsTypeIcon,
                 mCurrentState.activityIn, mCurrentState.activityOut, dataContentDescription,
                 dataContentDescriptionHtml, description, icons.isWide,
-                mCurrentState.subId, /* roaming= */ false, /* showTriangle= */ true);
+                mCurrentState.subId, /* roaming= */ false, /* showTriangle= */ true
+        );
+        callback.setMobileDataIndicators(mobileDataIndicators);
     }
 
     private int getCurrentIconIdForCarrierWifi() {
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
index 0a3e833..bbb2f1a 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
@@ -94,6 +94,7 @@
      */
     static final List<String> THEME_CATEGORIES = Lists.newArrayList(
             OVERLAY_CATEGORY_SYSTEM_PALETTE,
+            OVERLAY_CATEGORY_NEUTRAL_PALETTE,
             OVERLAY_CATEGORY_ICON_LAUNCHER,
             OVERLAY_CATEGORY_SHAPE,
             OVERLAY_CATEGORY_FONT,
@@ -107,6 +108,7 @@
     @VisibleForTesting
     static final Set<String> SYSTEM_USER_CATEGORIES = Sets.newHashSet(
             OVERLAY_CATEGORY_SYSTEM_PALETTE,
+            OVERLAY_CATEGORY_NEUTRAL_PALETTE,
             OVERLAY_CATEGORY_ACCENT_COLOR,
             OVERLAY_CATEGORY_FONT,
             OVERLAY_CATEGORY_SHAPE,
@@ -129,8 +131,9 @@
         mLauncherPackage = launcherPackage;
         mThemePickerPackage = themePickerPackage;
         mTargetPackageToCategories.put(ANDROID_PACKAGE, Sets.newHashSet(
-                OVERLAY_CATEGORY_SYSTEM_PALETTE, OVERLAY_CATEGORY_ACCENT_COLOR,
-                OVERLAY_CATEGORY_FONT, OVERLAY_CATEGORY_SHAPE, OVERLAY_CATEGORY_ICON_ANDROID));
+                OVERLAY_CATEGORY_SYSTEM_PALETTE, OVERLAY_CATEGORY_NEUTRAL_PALETTE,
+                OVERLAY_CATEGORY_ACCENT_COLOR, OVERLAY_CATEGORY_FONT, OVERLAY_CATEGORY_SHAPE,
+                OVERLAY_CATEGORY_ICON_ANDROID));
         mTargetPackageToCategories.put(SYSUI_PACKAGE,
                 Sets.newHashSet(OVERLAY_CATEGORY_ICON_SYSUI));
         mTargetPackageToCategories.put(SETTINGS_PACKAGE,
@@ -158,10 +161,10 @@
     void applyCurrentUserOverlays(
             Map<String, OverlayIdentifier> categoryToPackage,
             FabricatedOverlay[] pendingCreation,
-            Set<UserHandle> userHandles) {
+            int currentUser,
+            Set<UserHandle> managedProfiles) {
         // Disable all overlays that have not been specified in the user setting.
         final Set<String> overlayCategoriesToDisable = new HashSet<>(THEME_CATEGORIES);
-        overlayCategoriesToDisable.removeAll(categoryToPackage.keySet());
         final Set<String> targetPackagesToQuery = overlayCategoriesToDisable.stream()
                 .map(category -> mCategoryToTargetPackage.get(category))
                 .collect(Collectors.toSet());
@@ -172,6 +175,7 @@
                 .filter(o ->
                         mTargetPackageToCategories.get(o.targetPackageName).contains(o.category))
                 .filter(o -> overlayCategoriesToDisable.contains(o.category))
+                .filter(o -> !categoryToPackage.containsValue(new OverlayIdentifier(o.packageName)))
                 .filter(o -> o.isEnabled())
                 .map(o -> new Pair<>(o.category, o.packageName))
                 .collect(Collectors.toList());
@@ -183,17 +187,18 @@
             }
         }
 
-        // Toggle overlays in the order of THEME_CATEGORIES.
+        for (Pair<String, String> packageToDisable : overlaysToDisable) {
+            OverlayIdentifier overlayInfo = new OverlayIdentifier(packageToDisable.second);
+            setEnabled(transaction, overlayInfo, packageToDisable.first, currentUser,
+                    managedProfiles, false);
+        }
+
         for (String category : THEME_CATEGORIES) {
             if (categoryToPackage.containsKey(category)) {
                 OverlayIdentifier overlayInfo = categoryToPackage.get(category);
-                setEnabled(transaction, overlayInfo, category, userHandles, true);
+                setEnabled(transaction, overlayInfo, category, currentUser, managedProfiles, true);
             }
         }
-        for (Pair<String, String> packageToDisable : overlaysToDisable) {
-            OverlayIdentifier overlayInfo = new OverlayIdentifier(packageToDisable.second);
-            setEnabled(transaction, overlayInfo, packageToDisable.first, userHandles, false);
-        }
 
         mExecutor.execute(() -> {
             try {
@@ -210,18 +215,30 @@
     }
 
     private void setEnabled(OverlayManagerTransaction.Builder transaction,
-            OverlayIdentifier identifier, String category, Set<UserHandle> handles,
-            boolean enabled) {
+            OverlayIdentifier identifier, String category, int currentUser,
+            Set<UserHandle> managedProfiles, boolean enabled) {
         if (DEBUG) {
             Log.d(TAG, "setEnabled: " + identifier.getPackageName() + " category: "
                     + category + ": " + enabled);
         }
-        for (UserHandle userHandle : handles) {
-            transaction.setEnabled(identifier, enabled, userHandle.getIdentifier());
-        }
-        if (!handles.contains(UserHandle.SYSTEM) && SYSTEM_USER_CATEGORIES.contains(category)) {
+
+        transaction.setEnabled(identifier, enabled, currentUser);
+        if (currentUser != UserHandle.SYSTEM.getIdentifier()
+                && SYSTEM_USER_CATEGORIES.contains(category)) {
             transaction.setEnabled(identifier, enabled, UserHandle.SYSTEM.getIdentifier());
         }
+
+        // Do not apply Launcher or Theme picker overlays to managed users. Apps are not
+        // installed in there.
+        OverlayInfo overlayInfo = mOverlayManager.getOverlayInfo(identifier, UserHandle.SYSTEM);
+        if (overlayInfo == null || overlayInfo.targetPackageName.equals(mLauncherPackage)
+                || overlayInfo.targetPackageName.equals(mThemePickerPackage)) {
+            return;
+        }
+
+        for (UserHandle userHandle : managedProfiles) {
+            transaction.setEnabled(identifier, enabled, userHandle.getIdentifier());
+        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 1f222d8..f192287 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -43,7 +43,6 @@
 
 import androidx.annotation.NonNull;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dumpable;
 import com.android.systemui.SystemUI;
 import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -55,14 +54,13 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.settings.SecureSettings;
 
-import com.google.android.collect.Sets;
-
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.Executor;
@@ -86,13 +84,7 @@
 
     protected static final int PRIMARY = 0;
     protected static final int SECONDARY = 1;
-    protected static final int NEUTRAL = 1;
-
-    // If lock screen wallpaper colors should also be considered when selecting the theme.
-    // Doing this has performance impact, given that overlays would need to be swapped when
-    // the device unlocks.
-    @VisibleForTesting
-    static final boolean USE_LOCK_SCREEN_WALLPAPER = false;
+    protected static final int NEUTRAL = 2;
 
     private final ThemeOverlayApplier mThemeManager;
     private final UserManager mUserManager;
@@ -104,7 +96,6 @@
     private final WallpaperManager mWallpaperManager;
     private final KeyguardStateController mKeyguardStateController;
     private final boolean mIsMonetEnabled;
-    private WallpaperColors mLockColors;
     private WallpaperColors mSystemColors;
     // If fabricated overlays were already created for the current theme.
     private boolean mNeedsOverlayCreation;
@@ -118,6 +109,8 @@
     private FabricatedOverlay mSecondaryOverlay;
     // Neutral system colors overlay
     private FabricatedOverlay mNeutralOverlay;
+    // If wallpaper color event will be accepted and change the UI colors.
+    private boolean mAcceptColorEvents = true;
 
     @Inject
     public ThemeOverlayController(Context context, BroadcastDispatcher broadcastDispatcher,
@@ -147,13 +140,20 @@
         final IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
+        filter.addAction(Intent.ACTION_WALLPAPER_CHANGED);
         mBroadcastDispatcher.registerReceiver(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
-                if (DEBUG) Log.d(TAG, "Updating overlays for user switch / profile added.");
-                updateThemeOverlays();
+                if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())
+                        || Intent.ACTION_MANAGED_PROFILE_ADDED.equals(intent.getAction())) {
+                    if (DEBUG) Log.d(TAG, "Updating overlays for user switch / profile added.");
+                    reevaluateSystemTheme(true /* forceReload */);
+                } else if (Intent.ACTION_WALLPAPER_CHANGED.equals(intent.getAction())) {
+                    mAcceptColorEvents = true;
+                    Log.i(TAG, "Allowing color events again");
+                }
             }
-        }, filter, mBgExecutor, UserHandle.ALL);
+        }, filter, mMainExecutor, UserHandle.ALL);
         mSecureSettings.registerContentObserverForUser(
                 Settings.Secure.getUriFor(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES),
                 false,
@@ -163,7 +163,7 @@
                             int userId) {
                         if (DEBUG) Log.d(TAG, "Overlay changed for user: " + userId);
                         if (ActivityManager.getCurrentUser() == userId) {
-                            updateThemeOverlays();
+                            reevaluateSystemTheme(true /* forceReload */);
                         }
                     }
                 },
@@ -171,53 +171,34 @@
 
         // Upon boot, make sure we have the most up to date colors
         mBgExecutor.execute(() -> {
-            WallpaperColors lockColors = mWallpaperManager.getWallpaperColors(
-                    WallpaperManager.FLAG_LOCK);
             WallpaperColors systemColor = mWallpaperManager.getWallpaperColors(
                     WallpaperManager.FLAG_SYSTEM);
             mMainExecutor.execute(() -> {
-                if (USE_LOCK_SCREEN_WALLPAPER) {
-                    mLockColors = lockColors;
-                }
                 mSystemColors = systemColor;
-                reevaluateSystemTheme();
+                reevaluateSystemTheme(false /* forceReload */);
             });
         });
-        if (USE_LOCK_SCREEN_WALLPAPER) {
-            mKeyguardStateController.addCallback(new KeyguardStateController.Callback() {
-                @Override
-                public void onKeyguardShowingChanged() {
-                    if (mLockColors == null) {
-                        return;
-                    }
-                    // It's possible that the user has a lock screen wallpaper. On this case we'll
-                    // end up with different colors after unlocking.
-                    reevaluateSystemTheme();
-                }
-            });
-        }
         mWallpaperManager.addOnColorsChangedListener((wallpaperColors, which) -> {
-            if (USE_LOCK_SCREEN_WALLPAPER && (which & WallpaperManager.FLAG_LOCK) != 0) {
-                mLockColors = wallpaperColors;
-                if (DEBUG) {
-                    Log.d(TAG, "got new lock colors: " + wallpaperColors + " where: " + which);
-                }
+            if (!mAcceptColorEvents) {
+                Log.i(TAG, "Wallpaper color event rejected: " + wallpaperColors);
+                return;
             }
+            if (wallpaperColors != null && mAcceptColorEvents) {
+                mAcceptColorEvents = false;
+            }
+
             if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
                 mSystemColors = wallpaperColors;
                 if (DEBUG) {
                     Log.d(TAG, "got new lock colors: " + wallpaperColors + " where: " + which);
                 }
             }
-            reevaluateSystemTheme();
+            reevaluateSystemTheme(false /* forceReload */);
         }, null, UserHandle.USER_ALL);
     }
 
-    private void reevaluateSystemTheme() {
-        WallpaperColors currentColors =
-                mKeyguardStateController.isShowing() && mLockColors != null
-                        ? mLockColors : mSystemColors;
-
+    private void reevaluateSystemTheme(boolean forceReload) {
+        final WallpaperColors currentColors = mSystemColors;
         final int mainColor;
         final int accentCandidate;
         if (currentColors == null) {
@@ -228,7 +209,8 @@
             accentCandidate = getAccentColor(currentColors);
         }
 
-        if (mMainWallpaperColor == mainColor && mWallpaperAccentColor == accentCandidate) {
+        if (mMainWallpaperColor == mainColor && mWallpaperAccentColor == accentCandidate
+                && !forceReload) {
             return;
         }
 
@@ -309,6 +291,16 @@
             } catch (NumberFormatException e) {
                 Log.w(TAG, "Invalid color definition: " + systemPalette.getPackageName());
             }
+        } else if (!mIsMonetEnabled && systemPalette != null) {
+            try {
+                // It's possible that we flipped the flag off and still have a @ColorInt in the
+                // setting. We need to sanitize the input, otherwise the overlay transaction will
+                // fail.
+                Integer.parseInt(systemPalette.getPackageName().toLowerCase(), 16);
+                categoryToPackage.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE);
+            } catch (NumberFormatException e) {
+                // This is a package name. All good, let's continue
+            }
         }
 
         // Same for accent color.
@@ -322,6 +314,13 @@
             } catch (NumberFormatException e) {
                 Log.w(TAG, "Invalid color definition: " + accentPalette.getPackageName());
             }
+        } else if (!mIsMonetEnabled && accentPalette != null) {
+            try {
+                Integer.parseInt(accentPalette.getPackageName().toLowerCase(), 16);
+                categoryToPackage.remove(OVERLAY_CATEGORY_ACCENT_COLOR);
+            } catch (NumberFormatException e) {
+                // This is a package name. All good, let's continue
+            }
         }
 
         // Compatibility with legacy themes, where full packages were defined, instead of just
@@ -337,10 +336,10 @@
             categoryToPackage.put(OVERLAY_CATEGORY_ACCENT_COLOR, mSecondaryOverlay.getIdentifier());
         }
 
-        Set<UserHandle> userHandles = Sets.newHashSet(UserHandle.of(currentUser));
+        Set<UserHandle> managedProfiles = new HashSet<>();
         for (UserInfo userInfo : mUserManager.getEnabledProfiles(currentUser)) {
             if (userInfo.isManagedProfile()) {
-                userHandles.add(userInfo.getUserHandle());
+                managedProfiles.add(userInfo.getUserHandle());
             }
         }
         if (DEBUG) {
@@ -352,16 +351,15 @@
             mNeedsOverlayCreation = false;
             mThemeManager.applyCurrentUserOverlays(categoryToPackage, new FabricatedOverlay[] {
                     mPrimaryOverlay, mSecondaryOverlay, mNeutralOverlay
-            }, userHandles);
+            }, currentUser, managedProfiles);
         } else {
-            mThemeManager.applyCurrentUserOverlays(categoryToPackage, null, userHandles);
+            mThemeManager.applyCurrentUserOverlays(categoryToPackage, null, currentUser,
+                    managedProfiles);
         }
     }
 
     @Override
     public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
-        pw.println("USE_LOCK_SCREEN_WALLPAPER=" + USE_LOCK_SCREEN_WALLPAPER);
-        pw.println("mLockColors=" + mLockColors);
         pw.println("mSystemColors=" + mSystemColors);
         pw.println("mMainWallpaperColor=" + Integer.toHexString(mMainWallpaperColor));
         pw.println("mWallpaperAccentColor=" + Integer.toHexString(mWallpaperAccentColor));
@@ -370,5 +368,6 @@
         pw.println("mNeutralOverlay=" + mNeutralOverlay);
         pw.println("mIsMonetEnabled=" + mIsMonetEnabled);
         pw.println("mNeedsOverlayCreation=" + mNeedsOverlayCreation);
+        pw.println("mAcceptColorEvents=" + mAcceptColorEvents);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index df54eab..5dc7006 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -33,7 +33,11 @@
 
 import static com.android.systemui.volume.Events.DISMISS_REASON_SETTINGS_CLICKED;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ArgbEvaluator;
 import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
 import android.annotation.SuppressLint;
 import android.app.ActivityManager;
 import android.app.Dialog;
@@ -51,6 +55,9 @@
 import android.graphics.PixelFormat;
 import android.graphics.Region;
 import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.graphics.drawable.RotateDrawable;
 import android.media.AudioManager;
 import android.media.AudioSystem;
 import android.os.Debug;
@@ -81,6 +88,8 @@
 import android.view.animation.DecelerateInterpolator;
 import android.widget.FrameLayout;
 import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
 import android.widget.SeekBar;
 import android.widget.SeekBar.OnSeekBarChangeListener;
 import android.widget.TextView;
@@ -88,6 +97,7 @@
 
 import com.android.settingslib.Utils;
 import com.android.systemui.Dependency;
+import com.android.systemui.Interpolators;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.media.dialog.MediaOutputDialogFactory;
@@ -99,6 +109,8 @@
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.util.AlphaTintDrawableWrapper;
+import com.android.systemui.util.RoundedCornerProgressDrawable;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -124,8 +136,14 @@
     static final int DIALOG_ODI_CAPTIONS_TOOLTIP_TIMEOUT_MILLIS = 5000;
     static final int DIALOG_HOVERING_TIMEOUT_MILLIS = 16000;
 
+    private static final int DRAWER_ANIMATION_DURATION_SHORT = 175;
+    private static final int DRAWER_ANIMATION_DURATION = 250;
+
     private final int mDialogShowAnimationDurationMs;
     private final int mDialogHideAnimationDurationMs;
+    private final int mRingerDrawerItemSize;
+    private final boolean mShowVibrate;
+    private final int mRingerCount;
     private final boolean mShowLowMediaVolumeIcon;
     private final boolean mChangeVolumeRowTintWhenInactive;
 
@@ -140,6 +158,30 @@
     private ViewGroup mDialogView;
     private ViewGroup mDialogRowsView;
     private ViewGroup mRinger;
+
+    private ViewGroup mSelectedRingerContainer;
+    private ImageView mSelectedRingerIcon;
+
+    private ViewGroup mRingerDrawerContainer;
+    private ViewGroup mRingerDrawerMute;
+    private ViewGroup mRingerDrawerVibrate;
+    private ViewGroup mRingerDrawerNormal;
+    private ImageView mRingerDrawerMuteIcon;
+    private ImageView mRingerDrawerVibrateIcon;
+    private ImageView mRingerDrawerNormalIcon;
+
+    /**
+     * View that draws the 'selected' background behind one of the three ringer choices in the
+     * drawer.
+     */
+    private ViewGroup mRingerDrawerNewSelectionBg;
+
+    private final ValueAnimator mRingerDrawerIconColorAnimator = ValueAnimator.ofFloat(0f, 1f);
+    private ImageView mRingerDrawerIconAnimatingSelected;
+    private ImageView mRingerDrawerIconAnimatingDeselected;
+
+    private boolean mIsRingerDrawerOpen = false;
+
     private ImageButton mRingerIcon;
     private ViewGroup mODICaptionsView;
     private CaptionsToggleImageButton mODICaptionsIcon;
@@ -191,6 +233,12 @@
             mContext.getResources().getInteger(R.integer.config_dialogShowAnimationDurationMs);
         mDialogHideAnimationDurationMs =
             mContext.getResources().getInteger(R.integer.config_dialogHideAnimationDurationMs);
+        mRingerDrawerItemSize = mContext.getResources().getDimensionPixelSize(
+                R.dimen.volume_ringer_drawer_item_size);
+        mShowVibrate = mController.hasVibrator();
+
+        // Normal, mute, and possibly vibrate.
+        mRingerCount = mShowVibrate ? 3 : 2;
     }
 
     @Override
@@ -314,6 +362,20 @@
             mZenIcon = mRinger.findViewById(R.id.dnd_icon);
         }
 
+        mSelectedRingerIcon = mDialog.findViewById(R.id.volume_new_ringer_active_icon);
+        mSelectedRingerContainer = mDialog.findViewById(
+                R.id.volume_new_ringer_active_icon_container);
+
+        mRingerDrawerMute = mDialog.findViewById(R.id.volume_drawer_mute);
+        mRingerDrawerNormal = mDialog.findViewById(R.id.volume_drawer_normal);
+        mRingerDrawerVibrate = mDialog.findViewById(R.id.volume_drawer_vibrate);
+        mRingerDrawerMuteIcon = mDialog.findViewById(R.id.volume_drawer_mute_icon);
+        mRingerDrawerVibrateIcon = mDialog.findViewById(R.id.volume_drawer_vibrate_icon);
+        mRingerDrawerNormalIcon = mDialog.findViewById(R.id.volume_drawer_normal_icon);
+        mRingerDrawerNewSelectionBg = mDialog.findViewById(R.id.volume_drawer_selection_background);
+
+        setupRingerDrawer();
+
         mODICaptionsView = mDialog.findViewById(R.id.odi_captions);
         if (mODICaptionsView != null) {
             mODICaptionsIcon = mODICaptionsView.findViewById(R.id.odi_captions_icon);
@@ -475,40 +537,281 @@
 
         row.anim = null;
 
+        final LayerDrawable seekbarDrawable =
+                (LayerDrawable) mContext.getDrawable(R.drawable.volume_row_seekbar);
+
+        final LayerDrawable seekbarBgDrawable =
+                (LayerDrawable) seekbarDrawable.findDrawableByLayerId(android.R.id.background);
+
+        row.sliderBgSolid = seekbarBgDrawable.findDrawableByLayerId(
+                R.id.volume_seekbar_background_solid);
+
+        row.sliderBgIcon = (AlphaTintDrawableWrapper)
+                ((RotateDrawable) seekbarBgDrawable.findDrawableByLayerId(
+                        R.id.volume_seekbar_background_icon)).getDrawable();
+
+        final LayerDrawable seekbarProgressDrawable = (LayerDrawable)
+                ((RoundedCornerProgressDrawable) seekbarDrawable.findDrawableByLayerId(
+                        android.R.id.progress)).getDrawable();
+
+        row.sliderProgressSolid = seekbarProgressDrawable.findDrawableByLayerId(
+                R.id.volume_seekbar_progress_solid);
+
+        row.sliderProgressIcon = (AlphaTintDrawableWrapper)
+                ((RotateDrawable) seekbarProgressDrawable.findDrawableByLayerId(
+                        R.id.volume_seekbar_progress_icon)).getDrawable();
+
+        row.slider.setProgressDrawable(seekbarDrawable);
+        row.slider.setThumb(null);
+
         row.icon = row.view.findViewById(R.id.volume_row_icon);
-        row.icon.setImageResource(iconRes);
-        if (row.stream != AudioSystem.STREAM_ACCESSIBILITY) {
-            row.icon.setOnClickListener(v -> {
-                Events.writeEvent(Events.EVENT_ICON_CLICK, row.stream, row.iconState);
-                mController.setActiveStream(row.stream);
-                if (row.stream == AudioManager.STREAM_RING) {
-                    final boolean hasVibrator = mController.hasVibrator();
-                    if (mState.ringerModeInternal == AudioManager.RINGER_MODE_NORMAL) {
-                        if (hasVibrator) {
-                            mController.setRingerMode(AudioManager.RINGER_MODE_VIBRATE, false);
+
+        row.setIcon(iconRes, mContext.getTheme());
+
+        if (row.icon != null) {
+            if (row.stream != AudioSystem.STREAM_ACCESSIBILITY) {
+                row.icon.setOnClickListener(v -> {
+                    Events.writeEvent(Events.EVENT_ICON_CLICK, row.stream, row.iconState);
+                    mController.setActiveStream(row.stream);
+                    if (row.stream == AudioManager.STREAM_RING) {
+                        final boolean hasVibrator = mController.hasVibrator();
+                        if (mState.ringerModeInternal == AudioManager.RINGER_MODE_NORMAL) {
+                            if (hasVibrator) {
+                                mController.setRingerMode(AudioManager.RINGER_MODE_VIBRATE, false);
+                            } else {
+                                final boolean wasZero = row.ss.level == 0;
+                                mController.setStreamVolume(stream,
+                                        wasZero ? row.lastAudibleLevel : 0);
+                            }
                         } else {
-                            final boolean wasZero = row.ss.level == 0;
-                            mController.setStreamVolume(stream,
-                                    wasZero ? row.lastAudibleLevel : 0);
+                            mController.setRingerMode(
+                                    AudioManager.RINGER_MODE_NORMAL, false);
+                            if (row.ss.level == 0) {
+                                mController.setStreamVolume(stream, 1);
+                            }
                         }
                     } else {
-                        mController.setRingerMode(AudioManager.RINGER_MODE_NORMAL, false);
-                        if (row.ss.level == 0) {
-                            mController.setStreamVolume(stream, 1);
-                        }
+                        final boolean vmute = row.ss.level == row.ss.levelMin;
+                        mController.setStreamVolume(stream,
+                                vmute ? row.lastAudibleLevel : row.ss.levelMin);
                     }
-                } else {
-                    final boolean vmute = row.ss.level == row.ss.levelMin;
-                    mController.setStreamVolume(stream,
-                            vmute ? row.lastAudibleLevel : row.ss.levelMin);
-                }
-                row.userAttempt = 0;  // reset the grace period, slider updates immediately
-            });
-        } else {
-            row.icon.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+                    row.userAttempt = 0;  // reset the grace period, slider updates immediately
+                });
+            } else {
+                row.icon.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+            }
         }
     }
 
+    private void setRingerMode(int newRingerMode) {
+        Events.writeEvent(Events.EVENT_RINGER_TOGGLE, newRingerMode);
+        incrementManualToggleCount();
+        updateRingerH();
+        provideTouchFeedbackH(newRingerMode);
+        mController.setRingerMode(newRingerMode, false);
+        maybeShowToastH(newRingerMode);
+    }
+
+    private void setupRingerDrawer() {
+        mRingerDrawerContainer = mDialog.findViewById(R.id.volume_drawer_container);
+
+        if (mRingerDrawerContainer == null) {
+            return;
+        }
+
+        if (!mShowVibrate) {
+            mRingerDrawerVibrate.setVisibility(GONE);
+        }
+
+        // In portrait, add padding to the bottom to account for the height of the open ringer
+        // drawer.
+        if (!isLandscape()) {
+            mDialogView.setPadding(
+                    mDialogView.getPaddingLeft(),
+                    mDialogView.getPaddingTop(),
+                    mDialogView.getPaddingRight(),
+                    mDialogView.getPaddingBottom() + (mRingerCount - 1) * mRingerDrawerItemSize);
+        } else {
+            mDialogView.setPadding(
+                    mDialogView.getPaddingLeft() + (mRingerCount - 1) * mRingerDrawerItemSize,
+                    mDialogView.getPaddingTop(),
+                    mDialogView.getPaddingRight(),
+                    mDialogView.getPaddingBottom());
+        }
+
+        ((LinearLayout) mRingerDrawerContainer.findViewById(R.id.volume_drawer_options))
+                .setOrientation(isLandscape() ? LinearLayout.HORIZONTAL : LinearLayout.VERTICAL);
+
+        mSelectedRingerContainer.setOnClickListener(view -> {
+            if (mIsRingerDrawerOpen) {
+                hideRingerDrawer();
+            } else {
+                showRingerDrawer();
+            }
+        });
+
+        mRingerDrawerVibrate.setOnClickListener(
+                new RingerDrawerItemClickListener(RINGER_MODE_VIBRATE));
+        mRingerDrawerMute.setOnClickListener(
+                new RingerDrawerItemClickListener(RINGER_MODE_SILENT));
+        mRingerDrawerNormal.setOnClickListener(
+                new RingerDrawerItemClickListener(RINGER_MODE_NORMAL));
+
+        final int unselectedColor = Utils.getColorAccentDefaultColor(mContext);
+        final int selectedColor = Utils.getColorAttrDefaultColor(
+                mContext, android.R.attr.colorBackgroundFloating);
+
+        // Add an update listener that animates the deselected icon to the unselected color, and the
+        // selected icon to the selected color.
+        mRingerDrawerIconColorAnimator.addUpdateListener(
+                anim -> {
+                    final float currentValue = (float) anim.getAnimatedValue();
+                    final int curUnselectedColor = (int) ArgbEvaluator.getInstance().evaluate(
+                            currentValue, selectedColor, unselectedColor);
+                    final int curSelectedColor = (int) ArgbEvaluator.getInstance().evaluate(
+                            currentValue, unselectedColor, selectedColor);
+
+                    mRingerDrawerIconAnimatingDeselected.setColorFilter(curUnselectedColor);
+                    mRingerDrawerIconAnimatingSelected.setColorFilter(curSelectedColor);
+                });
+        mRingerDrawerIconColorAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mRingerDrawerIconAnimatingDeselected.clearColorFilter();
+                mRingerDrawerIconAnimatingSelected.clearColorFilter();
+            }
+        });
+        mRingerDrawerIconColorAnimator.setDuration(DRAWER_ANIMATION_DURATION_SHORT);
+    }
+
+    private ImageView getDrawerIconViewForMode(int mode) {
+        if (mode == RINGER_MODE_VIBRATE) {
+            return mRingerDrawerVibrateIcon;
+        } else if (mode == RINGER_MODE_SILENT) {
+            return mRingerDrawerMuteIcon;
+        } else {
+            return mRingerDrawerNormalIcon;
+        }
+    }
+
+    /**
+     * Translation to apply form the origin (either top or left) to overlap the selection background
+     * with the given mode in the drawer.
+     */
+    private float getTranslationInDrawerForRingerMode(int mode) {
+        return mode == RINGER_MODE_VIBRATE
+                ? -mRingerDrawerItemSize * 2
+                : mode == RINGER_MODE_SILENT
+                        ? -mRingerDrawerItemSize
+                        : 0;
+    }
+
+    /** Animates in the ringer drawer. */
+    private void showRingerDrawer() {
+        // Show all ringer icons except the currently selected one, since we're going to animate the
+        // ringer button to that position.
+        mRingerDrawerVibrateIcon.setVisibility(
+                mState.ringerModeInternal == RINGER_MODE_VIBRATE ? INVISIBLE : VISIBLE);
+        mRingerDrawerMuteIcon.setVisibility(
+                mState.ringerModeInternal == RINGER_MODE_SILENT ? INVISIBLE : VISIBLE);
+        mRingerDrawerNormalIcon.setVisibility(
+                mState.ringerModeInternal == RINGER_MODE_NORMAL ? INVISIBLE : VISIBLE);
+
+        // Hide the selection background - we use this to show a selection when one is
+        // tapped, so it should be invisible until that happens. However, position it below
+        // the currently selected ringer so that it's ready to animate.
+        mRingerDrawerNewSelectionBg.setAlpha(0f);
+
+        if (!isLandscape()) {
+            mRingerDrawerNewSelectionBg.setTranslationY(
+                    getTranslationInDrawerForRingerMode(mState.ringerModeInternal));
+        } else {
+            mRingerDrawerNewSelectionBg.setTranslationX(
+                    getTranslationInDrawerForRingerMode(mState.ringerModeInternal));
+        }
+
+        // Move the drawer so that the top/rightmost ringer choice overlaps with the selected ringer
+        // icon.
+        if (!isLandscape()) {
+            mRingerDrawerContainer.setTranslationY(mRingerDrawerItemSize * (mRingerCount - 1));
+        } else {
+            mRingerDrawerContainer.setTranslationX(mRingerDrawerItemSize * (mRingerCount - 1));
+        }
+        mRingerDrawerContainer.setAlpha(0f);
+        mRingerDrawerContainer.setVisibility(VISIBLE);
+
+        // Animate the drawer up and visible.
+        mRingerDrawerContainer.animate()
+                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+                // Vibrate is way farther up, so give the selected ringer icon a head start if
+                // vibrate is selected.
+                .setDuration(mState.ringerModeInternal == RINGER_MODE_VIBRATE
+                        ? DRAWER_ANIMATION_DURATION_SHORT
+                        : DRAWER_ANIMATION_DURATION)
+                .setStartDelay(mState.ringerModeInternal == RINGER_MODE_VIBRATE
+                        ? DRAWER_ANIMATION_DURATION - DRAWER_ANIMATION_DURATION_SHORT
+                        : 0)
+                .alpha(1f)
+                .translationX(0f)
+                .translationY(0f)
+                .start();
+
+        // Animate the selected ringer view up to that ringer's position in the drawer.
+        mSelectedRingerContainer.animate()
+                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+                .setDuration(DRAWER_ANIMATION_DURATION)
+                .withEndAction(() ->
+                        getDrawerIconViewForMode(mState.ringerModeInternal).setVisibility(VISIBLE));
+
+        if (!isLandscape()) {
+            mSelectedRingerContainer.animate()
+                    .translationY(getTranslationInDrawerForRingerMode(mState.ringerModeInternal))
+                    .start();
+        } else {
+            mSelectedRingerContainer.animate()
+                    .translationX(getTranslationInDrawerForRingerMode(mState.ringerModeInternal))
+                    .start();
+        }
+
+        mIsRingerDrawerOpen = true;
+    }
+
+    /** Animates away the ringer drawer. */
+    private void hideRingerDrawer() {
+
+        // If the ringer drawer isn't present, don't try to hide it.
+        if (mRingerDrawerContainer == null) {
+            return;
+        }
+
+        // Hide the drawer icon for the selected ringer - it's visible in the ringer button and we
+        // don't want to be able to see it while it animates away.
+        getDrawerIconViewForMode(mState.ringerModeInternal).setVisibility(INVISIBLE);
+
+        mRingerDrawerContainer.animate()
+                .alpha(0f)
+                .setDuration(DRAWER_ANIMATION_DURATION)
+                .setStartDelay(0)
+                .withEndAction(() -> mRingerDrawerContainer.setVisibility(INVISIBLE));
+
+        if (!isLandscape()) {
+            mRingerDrawerContainer.animate()
+                    .translationY(mRingerDrawerItemSize * 2)
+                    .start();
+        } else {
+            mRingerDrawerContainer.animate()
+                    .translationX(mRingerDrawerItemSize * 2)
+                    .start();
+        }
+
+        mSelectedRingerContainer.animate()
+                .translationX(0f)
+                .translationY(0f)
+                .start();
+
+        mIsRingerDrawerOpen = false;
+    }
+
     public void initSettingsH() {
         if (mSettingsView != null) {
             mSettingsView.setVisibility(
@@ -555,12 +858,8 @@
                         mController.setStreamVolume(AudioManager.STREAM_RING, 1);
                     }
                 }
-                Events.writeEvent(Events.EVENT_RINGER_TOGGLE, newRingerMode);
-                incrementManualToggleCount();
-                updateRingerH();
-                provideTouchFeedbackH(newRingerMode);
-                mController.setRingerMode(newRingerMode, false);
-                maybeShowToastH(newRingerMode);
+
+                setRingerMode(newRingerMode);
             });
         }
         updateRingerH();
@@ -809,6 +1108,8 @@
                     mDialog.dismiss();
                     tryToRemoveCaptionsTooltip();
                     mIsAnimatingDismiss = false;
+
+                    hideRingerDrawer();
                 }, 50));
         if (!isLandscape()) animator.translationX(mDialogView.getWidth() / 2.0f);
         animator.start();
@@ -889,12 +1190,14 @@
             switch (mState.ringerModeInternal) {
                 case AudioManager.RINGER_MODE_VIBRATE:
                     mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_vibrate);
+                    mSelectedRingerIcon.setImageResource(R.drawable.ic_volume_ringer_vibrate);
                     addAccessibilityDescription(mRingerIcon, RINGER_MODE_VIBRATE,
                             mContext.getString(R.string.volume_ringer_hint_mute));
                     mRingerIcon.setTag(Events.ICON_STATE_VIBRATE);
                     break;
                 case AudioManager.RINGER_MODE_SILENT:
                     mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_mute);
+                    mSelectedRingerIcon.setImageResource(R.drawable.ic_volume_ringer_mute);
                     mRingerIcon.setTag(Events.ICON_STATE_MUTE);
                     addAccessibilityDescription(mRingerIcon, RINGER_MODE_SILENT,
                             mContext.getString(R.string.volume_ringer_hint_unmute));
@@ -904,11 +1207,13 @@
                     boolean muted = (mAutomute && ss.level == 0) || ss.muted;
                     if (!isZenMuted && muted) {
                         mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_mute);
+                        mSelectedRingerIcon.setImageResource(R.drawable.ic_volume_ringer_mute);
                         addAccessibilityDescription(mRingerIcon, RINGER_MODE_NORMAL,
                                 mContext.getString(R.string.volume_ringer_hint_unmute));
                         mRingerIcon.setTag(Events.ICON_STATE_MUTE);
                     } else {
                         mRingerIcon.setImageResource(R.drawable.ic_volume_ringer);
+                        mSelectedRingerIcon.setImageResource(R.drawable.ic_volume_ringer);
                         if (mController.hasVibrator()) {
                             addAccessibilityDescription(mRingerIcon, RINGER_MODE_NORMAL,
                                     mContext.getString(R.string.volume_ringer_hint_vibrate));
@@ -1075,8 +1380,6 @@
 
         // update icon
         final boolean iconEnabled = (mAutomute || ss.muteSupported) && !zenMuted;
-        row.icon.setEnabled(iconEnabled);
-        row.icon.setAlpha(iconEnabled ? 1 : 0.5f);
         final int iconRes;
         if (isRingVibrate) {
             iconRes = R.drawable.ic_volume_ringer_vibrate;
@@ -1092,7 +1395,7 @@
                       ? R.drawable.ic_volume_media_low : row.iconRes;
         }
 
-        row.icon.setImageResource(iconRes);
+        row.setIcon(iconRes, mContext.getTheme());
         row.iconState =
                 iconRes == R.drawable.ic_volume_ringer_vibrate ? Events.ICON_STATE_VIBRATE
                 : (iconRes == R.drawable.ic_volume_media_bt_mute || iconRes == row.iconMuteRes)
@@ -1101,18 +1404,35 @@
                         || iconRes == R.drawable.ic_volume_media_low)
                         ? Events.ICON_STATE_UNMUTE
                 : Events.ICON_STATE_UNKNOWN;
-        if (iconEnabled) {
-            if (isRingStream) {
-                if (isRingVibrate) {
-                    row.icon.setContentDescription(mContext.getString(
-                            R.string.volume_stream_content_description_unmute,
-                            getStreamLabelH(ss)));
-                } else {
-                    if (mController.hasVibrator()) {
+
+        if (row.icon != null) {
+            if (iconEnabled) {
+                if (isRingStream) {
+                    if (isRingVibrate) {
                         row.icon.setContentDescription(mContext.getString(
-                                mShowA11yStream
-                                        ? R.string.volume_stream_content_description_vibrate_a11y
-                                        : R.string.volume_stream_content_description_vibrate,
+                                R.string.volume_stream_content_description_unmute,
+                                getStreamLabelH(ss)));
+                    } else {
+                        if (mController.hasVibrator()) {
+                            row.icon.setContentDescription(mContext.getString(
+                                    mShowA11yStream
+                                            ? R.string.volume_stream_content_description_vibrate_a11y
+                                            : R.string.volume_stream_content_description_vibrate,
+                                    getStreamLabelH(ss)));
+                        } else {
+                            row.icon.setContentDescription(mContext.getString(
+                                    mShowA11yStream
+                                            ? R.string.volume_stream_content_description_mute_a11y
+                                            : R.string.volume_stream_content_description_mute,
+                                    getStreamLabelH(ss)));
+                        }
+                    }
+                } else if (isA11yStream) {
+                    row.icon.setContentDescription(getStreamLabelH(ss));
+                } else {
+                    if (ss.muted || mAutomute && ss.level == 0) {
+                        row.icon.setContentDescription(mContext.getString(
+                                R.string.volume_stream_content_description_unmute,
                                 getStreamLabelH(ss)));
                     } else {
                         row.icon.setContentDescription(mContext.getString(
@@ -1122,23 +1442,9 @@
                                 getStreamLabelH(ss)));
                     }
                 }
-            } else if (isA11yStream) {
-                row.icon.setContentDescription(getStreamLabelH(ss));
             } else {
-                if (ss.muted || mAutomute && ss.level == 0) {
-                   row.icon.setContentDescription(mContext.getString(
-                           R.string.volume_stream_content_description_unmute,
-                           getStreamLabelH(ss)));
-                } else {
-                    row.icon.setContentDescription(mContext.getString(
-                            mShowA11yStream
-                                    ? R.string.volume_stream_content_description_mute_a11y
-                                    : R.string.volume_stream_content_description_mute,
-                            getStreamLabelH(ss)));
-                }
+                row.icon.setContentDescription(getStreamLabelH(ss));
             }
-        } else {
-            row.icon.setContentDescription(getStreamLabelH(ss));
         }
 
         // ensure tracking is disabled if zenMuted
@@ -1167,22 +1473,29 @@
         if (!useActiveColoring && !mChangeVolumeRowTintWhenInactive) {
             return;
         }
-        final ColorStateList tint = useActiveColoring
+        final ColorStateList colorTint = useActiveColoring
                 ? Utils.getColorAccent(mContext)
                 : Utils.getColorAttr(mContext, android.R.attr.colorForeground);
         final int alpha = useActiveColoring
-                ? Color.alpha(tint.getDefaultColor())
+                ? Color.alpha(colorTint.getDefaultColor())
                 : getAlphaAttr(android.R.attr.secondaryContentAlpha);
-        if (tint == row.cachedTint) return;
-        row.slider.setProgressTintList(tint);
-        row.slider.setThumbTintList(tint);
-        row.slider.setProgressBackgroundTintList(tint);
-        row.slider.setAlpha(((float) alpha) / 255);
-        row.icon.setImageTintList(tint);
-        row.icon.setImageAlpha(alpha);
-        row.cachedTint = tint;
+
+        final ColorStateList bgTint = Utils.getColorAttr(
+                mContext, android.R.attr.colorBackgroundFloating);
+
+        row.sliderProgressSolid.setTintList(colorTint);
+        row.sliderBgIcon.setTintList(colorTint);
+
+        row.sliderBgSolid.setTintList(bgTint);
+        row.sliderProgressIcon.setTintList(bgTint);
+
+        if (row.icon != null) {
+            row.icon.setImageTintList(colorTint);
+            row.icon.setImageAlpha(alpha);
+        }
+
         if (row.number != null) {
-            row.number.setTextColor(tint);
+            row.number.setTextColor(colorTint);
             row.number.setAlpha(alpha);
         }
     }
@@ -1538,6 +1851,10 @@
         private View view;
         private TextView header;
         private ImageButton icon;
+        private Drawable sliderBgSolid;
+        private AlphaTintDrawableWrapper sliderBgIcon;
+        private Drawable sliderProgressSolid;
+        private AlphaTintDrawableWrapper sliderProgressIcon;
         private SeekBar slider;
         private TextView number;
         private int stream;
@@ -1555,5 +1872,69 @@
         private int animTargetProgress;
         private int lastAudibleLevel = 1;
         private FrameLayout dndIcon;
+
+        void setIcon(int iconRes, Resources.Theme theme) {
+            if (icon != null) {
+                icon.setImageResource(iconRes);
+            }
+
+            sliderProgressIcon.setDrawable(view.getResources().getDrawable(iconRes, theme));
+            sliderBgIcon.setDrawable(view.getResources().getDrawable(iconRes, theme));
+        }
+    }
+
+    /**
+     * Click listener added to each ringer option in the drawer. This will initiate the animation to
+     * select and then close the ringer drawer, and actually change the ringer mode.
+     */
+    private class RingerDrawerItemClickListener implements View.OnClickListener {
+        private final int mClickedRingerMode;
+
+        RingerDrawerItemClickListener(int clickedRingerMode) {
+            mClickedRingerMode = clickedRingerMode;
+        }
+
+        @Override
+        public void onClick(View view) {
+            setRingerMode(mClickedRingerMode);
+
+            mRingerDrawerIconAnimatingSelected = getDrawerIconViewForMode(mClickedRingerMode);
+            mRingerDrawerIconAnimatingDeselected = getDrawerIconViewForMode(
+                    mState.ringerModeInternal);
+
+            // Begin switching the selected icon and deselected icon colors since the background is
+            // going to animate behind the new selection.
+            mRingerDrawerIconColorAnimator.start();
+
+            mSelectedRingerContainer.setVisibility(View.INVISIBLE);
+            mRingerDrawerNewSelectionBg.setAlpha(1f);
+            mRingerDrawerNewSelectionBg.animate()
+                    .setInterpolator(Interpolators.ACCELERATE_DECELERATE)
+                    .setDuration(DRAWER_ANIMATION_DURATION_SHORT)
+                    .withEndAction(() -> {
+                        mRingerDrawerNewSelectionBg.setAlpha(0f);
+
+                        if (!isLandscape()) {
+                            mSelectedRingerContainer.setTranslationY(
+                                    getTranslationInDrawerForRingerMode(mClickedRingerMode));
+                        } else {
+                            mSelectedRingerContainer.setTranslationX(
+                                    getTranslationInDrawerForRingerMode(mClickedRingerMode));
+                        }
+
+                        mSelectedRingerContainer.setVisibility(VISIBLE);
+                        hideRingerDrawer();
+                    });
+
+            if (!isLandscape()) {
+                mRingerDrawerNewSelectionBg.animate()
+                        .translationY(getTranslationInDrawerForRingerMode(mClickedRingerMode))
+                        .start();
+            } else {
+                mRingerDrawerNewSelectionBg.animate()
+                        .translationX(getTranslationInDrawerForRingerMode(mClickedRingerMode))
+                        .start();
+            }
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index 5d94659..78cd3a82 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -31,6 +31,7 @@
 import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.statusbar.IStatusBarService;
+import com.android.systemui.R;
 import com.android.systemui.dagger.WMComponent;
 import com.android.systemui.dagger.WMSingleton;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -76,6 +77,8 @@
 import com.android.wm.shell.sizecompatui.SizeCompatUIController;
 import com.android.wm.shell.splitscreen.SplitScreen;
 import com.android.wm.shell.splitscreen.SplitScreenController;
+import com.android.wm.shell.startingsurface.StartingSurface;
+import com.android.wm.shell.startingsurface.StartingWindowController;
 import com.android.wm.shell.transition.RemoteTransitions;
 import com.android.wm.shell.transition.Transitions;
 
@@ -97,7 +100,12 @@
 @Module
 public abstract class WMShellBaseModule {
 
-    private static final boolean ENABLE_SHELL_MAIN_THREAD = false;
+    /**
+     * Returns whether to enable a separate shell thread for the shell features.
+     */
+    private static boolean enableShellMainThread(Context context) {
+        return context.getResources().getBoolean(R.bool.config_enableShellMainThread);
+    }
 
     //
     // Shell Concurrency - Components used for managing threading in the Shell and SysUI
@@ -120,8 +128,8 @@
     @WMSingleton
     @Provides
     @ShellMainThread
-    public static Handler provideShellMainHandler(@Main Handler sysuiMainHandler) {
-        if (ENABLE_SHELL_MAIN_THREAD) {
+    public static Handler provideShellMainHandler(Context context, @Main Handler sysuiMainHandler) {
+        if (enableShellMainThread(context)) {
              HandlerThread mainThread = new HandlerThread("wmshell.main");
              mainThread.start();
              return mainThread.getThreadHandler();
@@ -135,9 +143,9 @@
     @WMSingleton
     @Provides
     @ShellMainThread
-    public static ShellExecutor provideShellMainExecutor(@ShellMainThread Handler mainHandler,
-            @Main ShellExecutor sysuiMainExecutor) {
-        if (ENABLE_SHELL_MAIN_THREAD) {
+    public static ShellExecutor provideShellMainExecutor(Context context,
+            @ShellMainThread Handler mainHandler, @Main ShellExecutor sysuiMainExecutor) {
+        if (enableShellMainThread(context)) {
             return new HandlerExecutor(mainHandler);
         }
         return sysuiMainExecutor;
@@ -367,6 +375,9 @@
         return new PipUiEventLogger(uiEventLogger, packageManager);
     }
 
+    @BindsOptionalOf
+    abstract PipTouchHandler optionalPipTouchHandler();
+
     //
     // Shell transitions
     //
@@ -409,10 +420,11 @@
             ShellTaskOrganizer shellTaskOrganizer,
             SyncTransactionQueue syncQueue, Context context,
             RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
-            @ShellMainThread ShellExecutor mainExecutor) {
+            @ShellMainThread ShellExecutor mainExecutor,
+            DisplayImeController displayImeController) {
         if (ActivityTaskManager.supportsSplitScreenMultiWindow(context)) {
             return Optional.of(new SplitScreenController(shellTaskOrganizer, syncQueue, context,
-                    rootTaskDisplayAreaOrganizer, mainExecutor));
+                    rootTaskDisplayAreaOrganizer, mainExecutor, displayImeController));
         } else {
             return Optional.empty();
         }
@@ -441,6 +453,22 @@
     @BindsOptionalOf
     abstract AppPairsController optionalAppPairs();
 
+    // Starting window
+
+    @WMSingleton
+    @Provides
+    static Optional<StartingSurface> provideStartingSurface(
+            StartingWindowController startingWindowController) {
+        return Optional.of(startingWindowController.asStartingSurface());
+    }
+
+    @WMSingleton
+    @Provides
+    static StartingWindowController provideStartingWindowController(Context context,
+            @ShellMainThread ShellExecutor mainExecutor) {
+        return new StartingWindowController(context, mainExecutor);
+    }
+
     //
     // Task view factory
     //
@@ -472,6 +500,8 @@
             Optional<LegacySplitScreenController> legacySplitScreenOptional,
             Optional<SplitScreenController> splitScreenOptional,
             Optional<AppPairsController> appPairsOptional,
+            Optional<StartingSurface> startingSurface,
+            Optional<PipTouchHandler> pipTouchHandlerOptional,
             FullscreenTaskListener fullscreenTaskListener,
             Transitions transitions,
             @ShellMainThread ShellExecutor mainExecutor) {
@@ -481,6 +511,8 @@
                 legacySplitScreenOptional,
                 splitScreenOptional,
                 appPairsOptional,
+                startingSurface,
+                pipTouchHandlerOptional,
                 fullscreenTaskListener,
                 transitions,
                 mainExecutor);
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 997b488..754b6a6 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -104,9 +104,10 @@
     @Provides
     static AppPairsController provideAppPairs(ShellTaskOrganizer shellTaskOrganizer,
             SyncTransactionQueue syncQueue, DisplayController displayController,
-            @ShellMainThread ShellExecutor mainExecutor) {
+            @ShellMainThread ShellExecutor mainExecutor,
+            DisplayImeController displayImeController) {
         return new AppPairsController(shellTaskOrganizer, syncQueue, displayController,
-                mainExecutor);
+                mainExecutor, displayImeController);
     }
 
     //
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index 854be1f..1783fa4 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -17,6 +17,7 @@
 package com.android.keyguard;
 
 import static android.view.WindowInsets.Type.ime;
+import static android.view.WindowInsets.Type.systemBars;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyLong;
@@ -24,13 +25,20 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.graphics.Insets;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+import android.testing.TestableResources;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowInsets;
 import android.view.WindowInsetsController;
+import android.widget.FrameLayout;
 
 import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 
 import org.junit.Before;
@@ -45,12 +53,21 @@
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper()
 public class KeyguardSecurityContainerTest extends SysuiTestCase {
+    private static final int SCREEN_WIDTH = 1600;
+    private static final int FAKE_MEASURE_SPEC =
+            View.MeasureSpec.makeMeasureSpec(SCREEN_WIDTH, View.MeasureSpec.EXACTLY);
+
+    private static final SecurityMode ONE_HANDED_SECURITY_MODE = SecurityMode.PIN;
+    private static final SecurityMode TWO_HANDED_SECURITY_MODE = SecurityMode.Password;
+
+
 
     @Rule
     public MockitoRule mRule = MockitoJUnit.rule();
 
     @Mock
     private WindowInsetsController mWindowInsetsController;
+
     @Mock
     private KeyguardSecurityViewFlipper mSecurityViewFlipper;
 
@@ -58,9 +75,18 @@
 
     @Before
     public void setup() {
+        // Needed here, otherwise when mKeyguardSecurityContainer is created below, it'll cache
+        // the real references (rather than the TestableResources that this call creates).
+        mContext.ensureTestableResources();
+        FrameLayout.LayoutParams securityViewFlipperLayoutParams = new FrameLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+
         when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController);
+        when(mSecurityViewFlipper.getLayoutParams()).thenReturn(securityViewFlipperLayoutParams);
         mKeyguardSecurityContainer = new KeyguardSecurityContainer(getContext());
         mKeyguardSecurityContainer.mSecurityViewFlipper = mSecurityViewFlipper;
+        mKeyguardSecurityContainer.addView(mSecurityViewFlipper, new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
     }
 
     @Test
@@ -69,4 +95,128 @@
         verify(mWindowInsetsController).controlWindowInsetsAnimation(eq(ime()), anyLong(), any(),
                 any(), any());
     }
-}
\ No newline at end of file
+
+    @Test
+    public void onMeasure_usesFullWidthWithoutOneHandedMode() {
+        setUpKeyguard(
+                /* deviceConfigCanUseOneHandedKeyguard= */false,
+                /* sysuiResourceCanUseOneHandedKeyguard= */ false,
+                ONE_HANDED_SECURITY_MODE);
+
+        mKeyguardSecurityContainer.measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
+
+        verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
+    }
+
+    @Test
+    public void onMeasure_usesFullWidthWithDeviceFlagDisabled() {
+        setUpKeyguard(
+                /* deviceConfigCanUseOneHandedKeyguard= */false,
+                /* sysuiResourceCanUseOneHandedKeyguard= */ true,
+                ONE_HANDED_SECURITY_MODE);
+
+        mKeyguardSecurityContainer.measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
+        verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
+    }
+
+    @Test
+    public void onMeasure_usesFullWidthWithSysUIFlagDisabled() {
+        setUpKeyguard(
+                /* deviceConfigCanUseOneHandedKeyguard= */true,
+                /* sysuiResourceCanUseOneHandedKeyguard= */ false,
+                ONE_HANDED_SECURITY_MODE);
+
+        mKeyguardSecurityContainer.measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
+        verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
+    }
+
+    @Test
+    public void onMeasure_usesHalfWidthWithFlagsEnabled() {
+        setUpKeyguard(
+                /* deviceConfigCanUseOneHandedKeyguard= */true,
+                /* sysuiResourceCanUseOneHandedKeyguard= */ true,
+                ONE_HANDED_SECURITY_MODE);
+
+        int halfWidthMeasureSpec =
+                View.MeasureSpec.makeMeasureSpec(SCREEN_WIDTH / 2, View.MeasureSpec.EXACTLY);
+        mKeyguardSecurityContainer.onMeasure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
+
+        verify(mSecurityViewFlipper).measure(halfWidthMeasureSpec, FAKE_MEASURE_SPEC);
+    }
+
+    @Test
+    public void onMeasure_usesFullWidthForFullScreenIme() {
+        setUpKeyguard(
+                /* deviceConfigCanUseOneHandedKeyguard= */true,
+                /* sysuiResourceCanUseOneHandedKeyguard= */ true,
+                TWO_HANDED_SECURITY_MODE);
+
+        mKeyguardSecurityContainer.measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
+        verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
+    }
+
+    @Test
+    public void onMeasure_respectsViewInsets() {
+        int imeInsetAmount = 100;
+        int systemBarInsetAmount = 10;
+
+        setUpKeyguard(
+                /* deviceConfigCanUseOneHandedKeyguard= */false,
+                /* sysuiResourceCanUseOneHandedKeyguard= */ false,
+                ONE_HANDED_SECURITY_MODE);
+
+        Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount);
+        Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount);
+
+        WindowInsets insets = new WindowInsets.Builder()
+                .setInsets(ime(), imeInset)
+                .setInsetsIgnoringVisibility(systemBars(), systemBarInset)
+                .build();
+
+        // It's reduced by the max of the systembar and IME, so just subtract IME inset.
+        int expectedHeightMeasureSpec = View.MeasureSpec.makeMeasureSpec(
+                SCREEN_WIDTH - imeInsetAmount, View.MeasureSpec.EXACTLY);
+
+        mKeyguardSecurityContainer.onApplyWindowInsets(insets);
+        mKeyguardSecurityContainer.measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
+        verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, expectedHeightMeasureSpec);
+    }
+
+    @Test
+    public void onMeasure_respectsViewInsets_largerSystembar() {
+        int imeInsetAmount = 0;
+        int systemBarInsetAmount = 10;
+
+        setUpKeyguard(
+                /* deviceConfigCanUseOneHandedKeyguard= */false,
+                /* sysuiResourceCanUseOneHandedKeyguard= */ false,
+                ONE_HANDED_SECURITY_MODE);
+
+        Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount);
+        Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount);
+
+        WindowInsets insets = new WindowInsets.Builder()
+                .setInsets(ime(), imeInset)
+                .setInsetsIgnoringVisibility(systemBars(), systemBarInset)
+                .build();
+
+        int expectedHeightMeasureSpec = View.MeasureSpec.makeMeasureSpec(
+                SCREEN_WIDTH - systemBarInsetAmount, View.MeasureSpec.EXACTLY);
+
+        mKeyguardSecurityContainer.onApplyWindowInsets(insets);
+        mKeyguardSecurityContainer.measure(FAKE_MEASURE_SPEC, FAKE_MEASURE_SPEC);
+        verify(mSecurityViewFlipper).measure(FAKE_MEASURE_SPEC, expectedHeightMeasureSpec);
+    }
+
+    private void setUpKeyguard(
+            boolean deviceConfigCanUseOneHandedKeyguard,
+            boolean sysuiResourceCanUseOneHandedKeyguard,
+            SecurityMode securityMode) {
+        TestableResources testableResources = mContext.getOrCreateTestableResources();
+        testableResources.addOverride(com.android.internal.R.bool.config_enableOneHandedKeyguard,
+                deviceConfigCanUseOneHandedKeyguard);
+        testableResources.addOverride(R.bool.can_use_one_handed_bouncer,
+                sysuiResourceCanUseOneHandedKeyguard);
+        mKeyguardSecurityContainer.updateLayoutForSecurityMode(securityMode);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
index 97cb873..2526990 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
@@ -16,8 +16,8 @@
 
 package com.android.systemui.appops;
 
-import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_CAMERA;
-import static android.hardware.SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE;
+import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
+import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE;
 
 import static junit.framework.TestCase.assertFalse;
 
@@ -125,9 +125,9 @@
         when(mAudioManager.getActiveRecordingConfigurations())
                 .thenReturn(List.of(mPausedMockRecording));
 
-        when(mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_CAMERA))
+        when(mSensorPrivacyController.isSensorBlocked(CAMERA))
                 .thenReturn(false);
-        when(mSensorPrivacyController.isSensorBlocked(INDIVIDUAL_SENSOR_CAMERA))
+        when(mSensorPrivacyController.isSensorBlocked(CAMERA))
                 .thenReturn(false);
 
         mController = new AppOpsControllerImpl(
@@ -505,7 +505,7 @@
         assertFalse(list.get(0).isDisabled());
 
         // Add a camera op, and disable the microphone. The camera op should be the only op returned
-        mController.onSensorBlockedChanged(INDIVIDUAL_SENSOR_MICROPHONE, true);
+        mController.onSensorBlockedChanged(MICROPHONE, true);
         mController.onOpActiveChanged(
                 AppOpsManager.OP_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
         mTestableLooper.processAllMessages();
@@ -515,7 +515,7 @@
 
 
         // Re enable the microphone, and verify the op returns
-        mController.onSensorBlockedChanged(INDIVIDUAL_SENSOR_MICROPHONE, false);
+        mController.onSensorBlockedChanged(MICROPHONE, false);
         mTestableLooper.processAllMessages();
 
         list = mController.getActiveAppOps();
@@ -538,7 +538,7 @@
         assertFalse(list.get(0).isDisabled());
 
         // Add an audio op, and disable the camera. The audio op should be the only op returned
-        mController.onSensorBlockedChanged(INDIVIDUAL_SENSOR_CAMERA, true);
+        mController.onSensorBlockedChanged(CAMERA, true);
         mController.onOpActiveChanged(
                 AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
         mTestableLooper.processAllMessages();
@@ -547,7 +547,7 @@
         assertEquals(AppOpsManager.OP_RECORD_AUDIO, list.get(0).getCode());
 
         // Re enable the camera, and verify the op returns
-        mController.onSensorBlockedChanged(INDIVIDUAL_SENSOR_CAMERA, false);
+        mController.onSensorBlockedChanged(CAMERA, false);
         mTestableLooper.processAllMessages();
 
         list = mController.getActiveAppOps();
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 3e873d1..fb778e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -150,7 +150,10 @@
     }
 
     @Test
-    public void dozeTimeTick() {
+    public void dozeTimeTick() throws RemoteException {
+        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
+        mFgExecutor.runAllReady();
         mUdfpsController.dozeTimeTick();
         verify(mUdfpsView).dozeTimeTick();
     }
@@ -239,8 +242,18 @@
     }
 
     @Test
-    public void registersViewForCallbacks() throws RemoteException {
-        verify(mStatusBarStateController).addCallback(mUdfpsView);
-        verify(mStatusBar).addExpansionChangedListener(mUdfpsView);
+    public void registersAndUnregistersViewForCallbacks() throws RemoteException {
+        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD);
+        mFgExecutor.runAllReady();
+        verify(mStatusBarStateController).addCallback(mUdfpsController.mStatusBarStateListener);
+        verify(mStatusBar).addExpansionChangedListener(
+                mUdfpsController.mStatusBarExpansionListener);
+
+        mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
+        mFgExecutor.runAllReady();
+        verify(mStatusBarStateController).removeCallback(mUdfpsController.mStatusBarStateListener);
+        verify(mStatusBar).removeExpansionChangedListener(
+                mUdfpsController.mStatusBarExpansionListener);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NearestTouchFrameTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NearestTouchFrameTest.java
index 5c179d4..c8f223b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NearestTouchFrameTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NearestTouchFrameTest.java
@@ -69,7 +69,7 @@
 
         mNearestTouchFrame.addView(left);
         mNearestTouchFrame.addView(right);
-        mNearestTouchFrame.onMeasure(0, 0);
+        mNearestTouchFrame.layout(0, 0, 30, 30);
 
         MotionEvent ev = MotionEvent.obtain(0, 0, 0,
                 12 /* x */, 5 /* y */, 0);
@@ -86,7 +86,7 @@
 
         mNearestTouchFrame.addView(left);
         mNearestTouchFrame.addView(right);
-        mNearestTouchFrame.onMeasure(0, 0);
+        mNearestTouchFrame.layout(0, 0, 30, 30);
 
         MotionEvent ev = MotionEvent.obtain(0, 0, 0,
                 12 /* x */, 5 /* y */, 0);
@@ -105,7 +105,7 @@
 
         mNearestTouchFrame.addView(left);
         mNearestTouchFrame.addView(right);
-        mNearestTouchFrame.onMeasure(0, 0);
+        mNearestTouchFrame.layout(0, 0, 30, 30);
 
         // Would go to left view if attached, but goes to right instead as left should be detached.
         MotionEvent ev = MotionEvent.obtain(0, 0, 0,
@@ -122,7 +122,7 @@
 
         mNearestTouchFrame.addView(left);
         mNearestTouchFrame.addView(right);
-        mNearestTouchFrame.onMeasure(0, 0);
+        mNearestTouchFrame.layout(0, 0, 30, 30);
 
         MotionEvent ev = MotionEvent.obtain(0, 0, 0,
                 12 /* x */, 5 /* y */, 0);
@@ -138,7 +138,7 @@
 
         mNearestTouchFrame.addView(left);
         mNearestTouchFrame.addView(right);
-        mNearestTouchFrame.onMeasure(0, 0);
+        mNearestTouchFrame.layout(0, 0, 30, 30);
 
         MotionEvent ev = MotionEvent.obtain(0, 0, 0,
                 18 /* x */, 5 /* y */, 0);
@@ -154,7 +154,7 @@
         mNearestTouchFrame.setIsVertical(true);
         mNearestTouchFrame.addView(top);
         mNearestTouchFrame.addView(bottom);
-        mNearestTouchFrame.onMeasure(0, 0);
+        mNearestTouchFrame.layout(0, 0, 30, 30);
 
         MotionEvent ev = MotionEvent.obtain(0, 0, 0,
                 5 /* x */, 12 /* y */, 0);
@@ -170,7 +170,7 @@
         mNearestTouchFrame.setIsVertical(true);
         mNearestTouchFrame.addView(top);
         mNearestTouchFrame.addView(bottom);
-        mNearestTouchFrame.onMeasure(0, 0);
+        mNearestTouchFrame.layout(0, 0, 30, 30);
 
         MotionEvent ev = MotionEvent.obtain(0, 0, 0,
                 5 /* x */, 18 /* y */, 0);
@@ -184,7 +184,7 @@
         View view = mockViewAt(0, 20, 10, 10);
         when(view.isAttachedToWindow()).thenReturn(false);
         mNearestTouchFrame.addView(view);
-        mNearestTouchFrame.onMeasure(0, 0);
+        mNearestTouchFrame.layout(0, 0, 30, 30);
 
         MotionEvent ev = MotionEvent.obtain(0, 0, 0, 5 /* x */, 18 /* y */, 0);
         mNearestTouchFrame.onTouchEvent(ev);
@@ -201,7 +201,7 @@
         mNearestTouchFrame.addView(view1);
         mNearestTouchFrame.addView(view2);
         mNearestTouchFrame.addView(view3);
-        mNearestTouchFrame.onMeasure(0, 0);
+        mNearestTouchFrame.layout(0, 0, 30, 30);
 
         MotionEvent ev = MotionEvent.obtain(0, 0, 0, 5 /* x */, 18 /* y */, 0);
         mNearestTouchFrame.onTouchEvent(ev);
@@ -213,11 +213,9 @@
     public void testCachedRegionsSplit_horizontal() {
         View left = mockViewAt(0, 0, 5, 20);
         View right = mockViewAt(15, 0, 5, 20);
-        mNearestTouchFrame.layout(0, 0, 20, 20);
-
         mNearestTouchFrame.addView(left);
         mNearestTouchFrame.addView(right);
-        mNearestTouchFrame.onMeasure(0, 0);
+        mNearestTouchFrame.layout(0, 0, 20, 20);
 
         Map<View, Rect> childRegions = mNearestTouchFrame.getFullTouchableChildRegions();
         assertEquals(2, childRegions.size());
@@ -231,12 +229,10 @@
     public void testCachedRegionsSplit_vertical() {
         View top = mockViewAt(0, 0, 20, 5);
         View bottom = mockViewAt(0, 15, 20, 5);
-        mNearestTouchFrame.layout(0, 0, 20, 20);
-        mNearestTouchFrame.setIsVertical(true);
-
         mNearestTouchFrame.addView(top);
         mNearestTouchFrame.addView(bottom);
-        mNearestTouchFrame.onMeasure(0, 0);
+        mNearestTouchFrame.setIsVertical(true);
+        mNearestTouchFrame.layout(0, 0, 20, 20);
 
         Map<View, Rect> childRegions = mNearestTouchFrame.getFullTouchableChildRegions();
         assertEquals(2, childRegions.size());
@@ -256,6 +252,8 @@
         }).when(v).getLocationInWindow(any());
         when(v.isClickable()).thenReturn(true);
         when(v.isAttachedToWindow()).thenReturn(true);
+        when(v.getWidth()).thenReturn(width);
+        when(v.getHeight()).thenReturn(height);
 
         // Stupid final methods.
         v.setLeft(0);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
index c8e9396..2a4b41c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
@@ -464,7 +464,7 @@
                 new PeopleSpaceTile
                         .Builder(SHORTCUT_ID_1, "userName", ICON, new Intent())
                         .setPackageName(PACKAGE_NAME)
-                        .setUid(0)
+                        .setUserHandle(new UserHandle(0))
                         .build();
         PeopleSpaceTile actual = PeopleSpaceUtils
                 .augmentTileFromNotification(mContext, tile, sbn);
@@ -482,7 +482,7 @@
                 new PeopleSpaceTile
                         .Builder(SHORTCUT_ID_3, "userName", ICON, new Intent())
                         .setPackageName(PACKAGE_NAME)
-                        .setUid(0)
+                        .setUserHandle(new UserHandle(0))
                         .build();
         PeopleSpaceTile actual = PeopleSpaceUtils
                 .augmentTileFromNotification(mContext, tile, sbn);
@@ -496,7 +496,7 @@
                 new PeopleSpaceTile
                         .Builder(SHORTCUT_ID_1, "userName", ICON, new Intent())
                         .setPackageName(PACKAGE_NAME)
-                        .setUid(0)
+                        .setUserHandle(new UserHandle(0))
                         .build();
         PeopleSpaceTile actual = PeopleSpaceUtils
                 .augmentTileFromVisibleNotifications(mContext, tile,
@@ -511,7 +511,7 @@
                 new PeopleSpaceTile
                         .Builder(SHORTCUT_ID_4, "userName", ICON, new Intent())
                         .setPackageName(PACKAGE_NAME)
-                        .setUid(0)
+                        .setUserHandle(new UserHandle(0))
                         .build();
         PeopleSpaceTile actual = PeopleSpaceUtils
                 .augmentTileFromVisibleNotifications(mContext, tile,
@@ -526,7 +526,7 @@
                 new PeopleSpaceTile
                         .Builder(SHORTCUT_ID_1, "userName", ICON, new Intent())
                         .setPackageName(PACKAGE_NAME)
-                        .setUid(0)
+                        .setUserHandle(new UserHandle(0))
                         .build();
         List<PeopleSpaceTile> actualList = PeopleSpaceUtils
                 .augmentTilesFromVisibleNotifications(
@@ -545,13 +545,13 @@
                 new PeopleSpaceTile
                         .Builder(SHORTCUT_ID_1, "userName", ICON, new Intent())
                         .setPackageName(PACKAGE_NAME)
-                        .setUid(1)
+                        .setUserHandle(new UserHandle(0))
                         .build();
         PeopleSpaceTile tile2 =
                 new PeopleSpaceTile
                         .Builder(SHORTCUT_ID_2, "userName2", ICON, new Intent())
                         .setPackageName(PACKAGE_NAME)
-                        .setUid(0)
+                        .setUserHandle(new UserHandle(0))
                         .build();
         List<PeopleSpaceTile> actualList = PeopleSpaceUtils
                 .augmentTilesFromVisibleNotifications(mContext, List.of(tile1, tile2),
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 1c8324c..800d859 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
@@ -109,7 +109,7 @@
             new PeopleSpaceTile
                     .Builder(SHORTCUT_ID, "username", ICON, new Intent())
                     .setPackageName(TEST_PACKAGE_A)
-                    .setUid(0)
+                    .setUserHandle(new UserHandle(1))
                     .setNotificationKey(NOTIFICATION_KEY + "1")
                     .setNotificationContent(NOTIFICATION_CONTENT)
                     .setNotificationDataUri(URI)
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 2dfd388..d40e6a4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
@@ -89,6 +89,8 @@
     private View mEdit;
     @Mock
     private MultiUserSwitch mMultiUserSwitch;
+    @Mock
+    private View mPowerMenuLiteView;
 
     private QSFooterViewController mController;
 
@@ -111,11 +113,12 @@
         when(mView.findViewById(R.id.build)).thenReturn(mBuildText);
         when(mView.findViewById(android.R.id.edit)).thenReturn(mEdit);
         when(mView.findViewById(R.id.multi_user_switch)).thenReturn(mMultiUserSwitch);
+        when(mView.findViewById(R.id.pm_lite)).thenReturn(mPowerMenuLiteView);
 
         mController = new QSFooterViewController(mView, mUserManager, mUserInfoController,
                 mActivityStarter, mDeviceProvisionedController, mUserTracker, mQSPanelController,
                 new QSDetailDisplayer(), mQuickQSPanelController, mFakeTunerService,
-                mMetricsLogger);
+                mMetricsLogger, false);
 
         mController.init();
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
index 0dfebab..a2a179e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
@@ -121,7 +121,6 @@
                 mQSTileHost, mQSCustomizerController, true, mMediaHost,
                 mQSTileRevealControllerFactory, mDumpManager, mMetricsLogger, mUiEventLogger,
                 mQSLogger, mBrightnessControllerFactory, mToggleSliderViewControllerFactory,
-                /* labelsFlag */ false,
                 mFeatureFlags
         );
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
index 5870200..cb380d5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
@@ -87,7 +87,6 @@
                 uiEventLogger,
                 qsLogger,
                 dumpManager,
-                false,
                 featureFlags
         )
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
index 1ec1da4..5a1bd5f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
@@ -36,6 +36,7 @@
 import com.android.keyguard.CarrierTextController;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
 import com.android.systemui.utils.leaks.LeakCheckedTest;
 import com.android.systemui.utils.os.FakeHandler;
 
@@ -215,10 +216,11 @@
 
     @Test // throws no Exception
     public void testSetMobileDataIndicators_invalidSim() {
-        mSignalCallback.setMobileDataIndicators(
+        MobileDataIndicators indicators = new MobileDataIndicators(
                 mock(NetworkController.IconState.class),
                 mock(NetworkController.IconState.class),
                 0, 0, true, true, "", "", "", true, 0, true, true);
+        mSignalCallback.setMobileDataIndicators(indicators);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
index 3d53062..62cc9b7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
@@ -49,7 +49,7 @@
         MockitoAnnotations.initMocks(this);
 
         TestableLooper.get(this).runWithLooper(() -> mTileAdapter =
-                new TileAdapter(mContext, mQSTileHost, new UiEventLoggerFake()));
+                new TileAdapter(mContext, mQSTileHost, new UiEventLoggerFake(), /* qsFlag */false));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
index faf43a2..1c29a81 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
@@ -46,6 +46,7 @@
 import com.android.systemui.statusbar.policy.HotspotController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.WifiIndicators;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -134,9 +135,11 @@
     public void testStateUnavailable_wifiDisabled() {
         NetworkController.IconState qsIcon =
                 new NetworkController.IconState(false, 0, "");
-        mSignalCallback.setWifiIndicators(false, mock(NetworkController.IconState.class),
+        WifiIndicators indicators = new WifiIndicators(
+                false, mock(NetworkController.IconState.class),
                 qsIcon, false,false, "",
                 false, "");
+        mSignalCallback.setWifiIndicators(indicators);
         mTestableLooper.processAllMessages();
 
         assertEquals(Tile.STATE_UNAVAILABLE, mCastTile.getState().state);
@@ -146,9 +149,11 @@
     public void testStateUnavailable_wifiNotConnected() {
         NetworkController.IconState qsIcon =
                 new NetworkController.IconState(false, 0, "");
-        mSignalCallback.setWifiIndicators(true, mock(NetworkController.IconState.class),
+        WifiIndicators indicators = new WifiIndicators(
+                true, mock(NetworkController.IconState.class),
                 qsIcon, false,false, "",
                 false, "");
+        mSignalCallback.setWifiIndicators(indicators);
         mTestableLooper.processAllMessages();
 
         assertEquals(Tile.STATE_UNAVAILABLE, mCastTile.getState().state);
@@ -157,9 +162,11 @@
     private void enableWifiAndProcessMessages() {
         NetworkController.IconState qsIcon =
                 new NetworkController.IconState(true, 0, "");
-        mSignalCallback.setWifiIndicators(true, mock(NetworkController.IconState.class),
+        WifiIndicators indicators = new WifiIndicators(
+                true, mock(NetworkController.IconState.class),
                 qsIcon, false,false, "",
                 false, "");
+        mSignalCallback.setWifiIndicators(indicators);
         mTestableLooper.processAllMessages();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
index ffd747e..880c290 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
@@ -18,10 +18,12 @@
 
 import static junit.framework.Assert.assertEquals;
 
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.os.Handler;
-import android.provider.Settings;
 import android.service.quicksettings.Tile;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -34,9 +36,9 @@
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.ReduceBrightColorsController;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.settings.UserTracker;
-import com.android.systemui.util.settings.FakeSettings;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -60,8 +62,9 @@
     private QSLogger mQSLogger;
     @Mock
     private UserTracker mUserTracker;
+    @Mock
+    private ReduceBrightColorsController mReduceBrightColorsController;
 
-    private FakeSettings mFakeSettings;
     private TestableLooper mTestableLooper;
     private ReduceBrightColorsTile mTile;
 
@@ -72,24 +75,23 @@
         mTestableLooper = TestableLooper.get(this);
 
         when(mHost.getContext()).thenReturn(mContext);
-        mFakeSettings = new FakeSettings();
 
         mTile = new ReduceBrightColorsTile(
                 true,
+                mReduceBrightColorsController,
                 mHost,
                 mTestableLooper.getLooper(),
                 new Handler(mTestableLooper.getLooper()),
                 mMetricsLogger,
                 mStatusBarStateController,
                 mActivityStarter,
-                mQSLogger,
-                mUserTracker,
-                mFakeSettings
+                mQSLogger
         );
     }
 
     @Test
     public void testNotActive() {
+        when(mReduceBrightColorsController.isReduceBrightColorsActivated()).thenReturn(false);
         mTile.refreshState();
         mTestableLooper.processAllMessages();
 
@@ -100,33 +102,27 @@
 
     @Test
     public void testActive() {
-        mFakeSettings.putIntForUser(
-                Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED,
-                1,
-                mUserTracker.getUserId());
+        when(mReduceBrightColorsController.isReduceBrightColorsActivated()).thenReturn(true);
         mTile.refreshState();
         mTestableLooper.processAllMessages();
 
-        assertActiveState();
+        assertEquals(Tile.STATE_ACTIVE, mTile.getState().state);
+        assertEquals(mTile.getState().label.toString(),
+                mContext.getString(R.string.quick_settings_reduce_bright_colors_label));
     }
 
     @Test
-    public void testActive_clicked_isActive() {
+    public void testActive_clicked_featureIsActivated() {
+        when(mReduceBrightColorsController.isReduceBrightColorsActivated()).thenReturn(false);
         mTile.refreshState();
         mTestableLooper.processAllMessages();
         // Validity check
         assertEquals(Tile.STATE_INACTIVE, mTile.getState().state);
 
         mTile.handleClick();
-        mTile.refreshState();
-        mTestableLooper.processAllMessages();
 
-        assertActiveState();
+        verify(mReduceBrightColorsController, times(1))
+                .setReduceBrightColorsActivated(eq(true));
     }
 
-    private void assertActiveState() {
-        assertEquals(Tile.STATE_ACTIVE, mTile.getState().state);
-        assertEquals(mTile.getState().label.toString(),
-                mContext.getString(R.string.quick_settings_reduce_bright_colors_label));
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScrollCaptureConnection.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScrollCaptureConnection.java
index a75c39c..9e62a62 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScrollCaptureConnection.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScrollCaptureConnection.java
@@ -24,6 +24,7 @@
 import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
 import android.graphics.RenderNode;
+import android.os.ICancellationSignal;
 import android.os.RemoteException;
 import android.view.IScrollCaptureCallbacks;
 import android.view.IScrollCaptureConnection;
@@ -46,7 +47,7 @@
     }
 
     @Override
-    public void startCapture(Surface surface) {
+    public ICancellationSignal startCapture(Surface surface) {
         mSurface = surface;
         mHwuiContext = new HwuiContext(false, surface);
         mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@@ -56,27 +57,28 @@
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
+        return null;
     }
 
     @Override
-    public void requestImage(Rect rect) {
+    public ICancellationSignal requestImage(Rect rect) {
         Canvas canvas = mHwuiContext.lockCanvas(rect.width(), rect.height());
         mPaint.setColor(mColors[mNextColor]);
         canvas.drawRect(rect, mPaint);
         mNextColor = (mNextColor++) % mColors.length;
-        long frameNumber = mSurface.getNextFrameNumber();
         mHwuiContext.unlockAndPost(canvas);
         try {
-            mCallbacks.onCaptureBufferSent(frameNumber, rect);
+            mCallbacks.onImageRequestCompleted(0, rect);
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
+        return null;
     }
 
     @Override
-    public void endCapture() {
+    public ICancellationSignal endCapture() {
         try {
-            mCallbacks.onConnectionClosed();
+            mCallbacks.onCaptureEnded();
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         } finally {
@@ -84,6 +86,12 @@
             mSurface = null;
             mCallbacks = null;
         }
+        return null;
+    }
+
+    @Override
+    public void close() throws RemoteException {
+
     }
 
     // From android.view.Surface, but issues render requests synchronously with waitForPresent(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
index 580f800..802b462 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
@@ -29,7 +29,6 @@
 import static java.util.Objects.requireNonNull;
 
 import android.content.Context;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
 import android.os.RemoteException;
@@ -37,6 +36,7 @@
 import android.view.Display;
 import android.view.IScrollCaptureCallbacks;
 import android.view.IWindowManager;
+import android.view.ScrollCaptureResponse;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
@@ -82,10 +82,11 @@
     public void testBasicClientFlow() throws RemoteException {
         doAnswer((Answer<Void>) invocation -> {
             IScrollCaptureCallbacks cb = invocation.getArgument(3);
-            cb.onConnected(
-                    new FakeScrollCaptureConnection(cb),
-                    /* scrollBounds */ new Rect(0, 0, 100, 100),
-                    /* positionInWindow */ new Point(0, 0));
+            cb.onScrollCaptureResponse(new ScrollCaptureResponse.Builder()
+                    .setBoundsInWindow(new Rect(0, 0, 100, 100))
+                    .setWindowBounds(new Rect(0, 0, 100, 100))
+                    .setConnection(new FakeScrollCaptureConnection(cb))
+                    .build());
             return null;
         }).when(mWm).requestScrollCapture(/* displayId */ anyInt(), /* token */  isNull(),
                 /* taskId */ anyInt(), any(IScrollCaptureCallbacks.class));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureTest.java
index 2b3ca7c..6564d58 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureTest.java
@@ -19,15 +19,14 @@
 import static org.junit.Assert.fail;
 
 import android.content.Intent;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.RemoteException;
 import android.testing.AndroidTestingRunner;
 import android.util.Log;
 import android.view.Display;
 import android.view.IScrollCaptureCallbacks;
-import android.view.IScrollCaptureConnection;
 import android.view.IWindowManager;
+import android.view.ScrollCaptureResponse;
 import android.view.WindowManagerGlobal;
 
 import androidx.test.filters.SmallTest;
@@ -67,31 +66,27 @@
             wms.requestScrollCapture(Display.DEFAULT_DISPLAY, null, -1,
                     new IScrollCaptureCallbacks.Stub() {
                         @Override
-                        public void onConnected(
-                                IScrollCaptureConnection connection, Rect scrollBounds,
-                                Point positionInWindow) {
-                            Log.d(TAG,
-                                    "client connected: " + connection + "[scrollBounds= "
-                                            + scrollBounds + ", "
-                                            + "positionInWindow=" + positionInWindow + "]");
+                        public void onScrollCaptureResponse(ScrollCaptureResponse response)
+                                throws RemoteException {
+                            Log.d(TAG, "onScrollCaptureResponse: " + response);
                             latch.countDown();
                         }
 
                         @Override
-                        public void onUnavailable() {
-                        }
-
-                        @Override
                         public void onCaptureStarted() {
                         }
 
                         @Override
-                        public void onCaptureBufferSent(long frameNumber, Rect capturedArea) {
+                        public void onImageRequestCompleted(int i, Rect rect)
+                                throws RemoteException {
+
                         }
 
                         @Override
-                        public void onConnectionClosed() {
+                        public void onCaptureEnded() throws RemoteException {
+
                         }
+
                     });
         } catch (RemoteException e) {
             Log.e(TAG, "request failed", e);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index ce14bca..7ff056e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar;
 
+import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
+import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
 import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
 
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_DISCLOSURE;
@@ -40,6 +42,7 @@
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.TrustManager;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.UserInfo;
@@ -94,8 +97,12 @@
 
     private static final String ORGANIZATION_NAME = "organization";
 
+    private static final ComponentName DEVICE_OWNER_COMPONENT = new ComponentName("com.android.foo",
+            "bar");
+
     private String mDisclosureWithOrganization;
     private String mDisclosureGeneric;
+    private String mFinancedDisclosureWithOrganization;
 
     @Mock
     private DevicePolicyManager mDevicePolicyManager;
@@ -156,6 +163,8 @@
         mDisclosureWithOrganization = mContext.getString(R.string.do_disclosure_with_name,
                 ORGANIZATION_NAME);
         mDisclosureGeneric = mContext.getString(R.string.do_disclosure_generic);
+        mFinancedDisclosureWithOrganization = mContext.getString(
+                R.string.do_financed_disclosure_with_name, ORGANIZATION_NAME);
 
         when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
         when(mKeyguardUpdateMonitor.isScreenOn()).thenReturn(true);
@@ -165,6 +174,11 @@
                 .thenReturn(mIndicationAreaBottom);
         when(mIndicationArea.findViewById(R.id.keyguard_indication_text)).thenReturn(mTextView);
 
+        when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser())
+                .thenReturn(DEVICE_OWNER_COMPONENT);
+        when(mDevicePolicyManager.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
+                .thenReturn(DEVICE_OWNER_TYPE_DEFAULT);
+
         mWakeLock = new WakeLockFake();
         mWakeLockBuilder = new WakeLockFake.Builder(mContext);
         mWakeLockBuilder.setWakeLock(mWakeLock);
@@ -372,6 +386,22 @@
     }
 
     @Test
+    public void disclosure_deviceOwner_financedDeviceWithOrganizationName() {
+        createController();
+
+        when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
+        when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(ORGANIZATION_NAME);
+        when(mDevicePolicyManager.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
+                .thenReturn(DEVICE_OWNER_TYPE_FINANCED);
+        sendUpdateDisclosureBroadcast();
+
+        verify(mRotateTextViewController).updateIndication(eq(INDICATION_TYPE_DISCLOSURE),
+                mKeyguardIndicationCaptor.capture(), eq(false));
+        assertThat(mKeyguardIndicationCaptor.getValue().getMessage())
+                .isEqualTo(mFinancedDisclosureWithOrganization);
+    }
+
+    @Test
     public void transientIndication_holdsWakeLock_whenDozing() {
         createController();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
index 71f146b..f31639c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
@@ -35,6 +35,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
+import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.drawable.Icon;
 import android.os.UserHandle;
@@ -121,4 +122,13 @@
         assertEquals("Transparent backgrounds should fallback to drawable color",
                 color, mIconView.getStaticDrawableColor());
     }
+
+    @Test
+    public void testGiantImageNotAllowed() {
+        Bitmap largeBitmap = Bitmap.createBitmap(1000, 1000, Bitmap.Config.ARGB_8888);
+        Icon icon = Icon.createWithBitmap(largeBitmap);
+        StatusBarIcon largeIcon = new StatusBarIcon(UserHandle.ALL, "mockPackage",
+                icon, 0, 0, "");
+        assertFalse(mIconView.set(largeIcon));
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index ce0f122..9a5482c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -377,8 +377,6 @@
         // THEN we send the dismissal to system server
         verify(mStatusBarService).onNotificationClear(
                 notif2.sbn.getPackageName(),
-                notif2.sbn.getTag(),
-                88,
                 notif2.sbn.getUser().getIdentifier(),
                 notif2.sbn.getKey(),
                 stats.dismissalSurface,
@@ -528,8 +526,6 @@
         // THEN we never send the dismissal to system server
         verify(mStatusBarService, never()).onNotificationClear(
                 notif.sbn.getPackageName(),
-                notif.sbn.getTag(),
-                47,
                 notif.sbn.getUser().getIdentifier(),
                 notif.sbn.getKey(),
                 stats.dismissalSurface,
@@ -566,8 +562,6 @@
         // THEN the notification is never sent to system server to dismiss
         verify(mStatusBarService, never()).onNotificationClear(
                 eq(notif.sbn.getPackageName()),
-                eq(notif.sbn.getTag()),
-                eq(47),
                 eq(notif.sbn.getUser().getIdentifier()),
                 eq(notif.sbn.getKey()),
                 anyInt(),
@@ -596,8 +590,6 @@
         // THEN we send the dismissal to system server
         verify(mStatusBarService).onNotificationClear(
                 eq(notif.sbn.getPackageName()),
-                eq(notif.sbn.getTag()),
-                eq(47),
                 eq(notif.sbn.getUser().getIdentifier()),
                 eq(notif.sbn.getKey()),
                 anyInt(),
@@ -1125,8 +1117,6 @@
         // THEN we send the dismissals to system server
         verify(mStatusBarService).onNotificationClear(
                 notif1.sbn.getPackageName(),
-                notif1.sbn.getTag(),
-                47,
                 notif1.sbn.getUser().getIdentifier(),
                 notif1.sbn.getKey(),
                 stats1.dismissalSurface,
@@ -1135,8 +1125,6 @@
 
         verify(mStatusBarService).onNotificationClear(
                 notif2.sbn.getPackageName(),
-                notif2.sbn.getTag(),
-                88,
                 notif2.sbn.getUser().getIdentifier(),
                 notif2.sbn.getKey(),
                 stats2.dismissalSurface,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index 82d1f43..094a70e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.android.systemui.qs.dagger.QSFlagsModule.RBC_AVAILABLE;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
@@ -47,6 +49,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.qs.AutoAddTracker;
 import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.ReduceBrightColorsController;
 import com.android.systemui.qs.SecureSetting;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.CastController.CastDevice;
@@ -67,6 +70,8 @@
 import java.util.Collections;
 import java.util.List;
 
+import javax.inject.Named;
+
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
 @SmallTest
@@ -88,9 +93,11 @@
     @Mock private DataSaverController mDataSaverController;
     @Mock private ManagedProfileController mManagedProfileController;
     @Mock private NightDisplayListener mNightDisplayListener;
+    @Mock private ReduceBrightColorsController mReduceBrightColorsController;
     @Mock(answer = Answers.RETURNS_SELF)
     private AutoAddTracker.Builder mAutoAddTrackerBuilder;
     @Mock private Context mUserContext;
+    private final boolean mIsReduceBrightColorsAvailable = true;
 
     private AutoTileManager mAutoTileManager;
     private SecureSettings mSecureSettings;
@@ -130,7 +137,9 @@
             DataSaverController dataSaverController,
             ManagedProfileController managedProfileController,
             NightDisplayListener nightDisplayListener,
-            CastController castController) {
+            CastController castController,
+            ReduceBrightColorsController reduceBrightColorsController,
+            @Named(RBC_AVAILABLE) boolean isReduceBrightColorsAvailable) {
         return new AutoTileManager(context, autoAddTrackerBuilder, mQsTileHost,
                 Handler.createAsync(TestableLooper.get(this).getLooper()),
                 mSecureSettings,
@@ -138,13 +147,15 @@
                 dataSaverController,
                 managedProfileController,
                 nightDisplayListener,
-                castController);
+                castController,
+                reduceBrightColorsController,
+                isReduceBrightColorsAvailable);
     }
 
     private AutoTileManager createAutoTileManager(Context context) {
         return createAutoTileManager(context, mAutoAddTrackerBuilder, mHotspotController,
                 mDataSaverController, mManagedProfileController, mNightDisplayListener,
-                mCastController);
+                mCastController, mReduceBrightColorsController, mIsReduceBrightColorsAvailable);
     }
 
     @Test
@@ -157,9 +168,11 @@
         ManagedProfileController mPC = mock(ManagedProfileController.class);
         NightDisplayListener nDS = mock(NightDisplayListener.class);
         CastController cC = mock(CastController.class);
+        ReduceBrightColorsController rBC = mock(ReduceBrightColorsController.class);
 
         AutoTileManager manager =
-                createAutoTileManager(mock(Context.class), builder, hC, dSC, mPC, nDS, cC);
+                createAutoTileManager(mock(Context.class), builder, hC, dSC, mPC, nDS, cC, rBC,
+                        true);
 
         verify(tracker, never()).initialize();
         verify(hC, never()).addCallback(any());
@@ -167,6 +180,7 @@
         verify(mPC, never()).addCallback(any());
         verify(nDS, never()).setCallback(any());
         verify(cC, never()).addCallback(any());
+        verify(rBC, never()).addCallback(any());
         assertNull(manager.getSecureSettingForKey(TEST_SETTING));
         assertNull(manager.getSecureSettingForKey(TEST_SETTING_COMPONENT));
     }
@@ -207,6 +221,10 @@
             inOrderNightDisplay.verify(mNightDisplayListener).setCallback(isNotNull());
         }
 
+        InOrder inOrderReduceBrightColors = inOrder(mReduceBrightColorsController);
+        inOrderReduceBrightColors.verify(mReduceBrightColorsController).removeCallback(any());
+        inOrderReduceBrightColors.verify(mReduceBrightColorsController).addCallback(any());
+
         InOrder inOrderCast = inOrder(mCastController);
         inOrderCast.verify(mCastController).removeCallback(any());
         inOrderCast.verify(mCastController).addCallback(any());
@@ -247,6 +265,10 @@
             inOrderNightDisplay.verify(mNightDisplayListener).setCallback(isNotNull());
         }
 
+        InOrder inOrderReduceBrightColors = inOrder(mReduceBrightColorsController);
+        inOrderReduceBrightColors.verify(mReduceBrightColorsController).removeCallback(any());
+        inOrderReduceBrightColors.verify(mReduceBrightColorsController).addCallback(any());
+
         InOrder inOrderCast = inOrder(mCastController);
         inOrderCast.verify(mCastController).removeCallback(any());
         inOrderCast.verify(mCastController, never()).addCallback(any());
@@ -315,6 +337,18 @@
         verify(mQsTileHost, never()).addTile("night");
     }
 
+    @Test
+    public void reduceBrightColorsTileAdded_whenActivated() {
+        mAutoTileManager.mReduceBrightColorsCallback.onActivated(true);
+        verify(mQsTileHost).addTile("reduce_brightness");
+    }
+
+    @Test
+    public void reduceBrightColorsTileNotAdded_whenDeactivated() {
+        mAutoTileManager.mReduceBrightColorsCallback.onActivated(false);
+        verify(mQsTileHost, never()).addTile("reduce_brightness");
+    }
+
     private static List<CastDevice> buildFakeCastDevice(boolean isCasting) {
         CastDevice cd = new CastDevice();
         cd.state = isCasting ? CastDevice.STATE_CONNECTED : CastDevice.STATE_DISCONNECTED;
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 dd31f52..ec5114e 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
@@ -71,10 +71,8 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.biometrics.AuthController;
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.classifier.FalsingManagerFake;
-import com.android.systemui.controls.dagger.ControlsComponent;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.media.MediaDataManager;
 import com.android.systemui.media.MediaHierarchyManager;
@@ -222,10 +220,6 @@
     @Mock
     private FeatureFlags mFeatureFlags;
     @Mock
-    private ControlsComponent mControlsComponent;
-    @Mock
-    private BroadcastDispatcher mBroadcastDispatcher;
-    @Mock
     private AmbientState mAmbientState;
     @Mock
     private UserManager mUserManager;
@@ -328,9 +322,7 @@
                 mUserManager,
                 mMediaDataManager,
                 mAmbientState,
-                mFeatureFlags,
-                mControlsComponent,
-                mBroadcastDispatcher);
+                mFeatureFlags);
         mNotificationPanelViewController.initDependencies(
                 mStatusBar,
                 mNotificationShelfController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
index 67c1a08..2418243 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
@@ -30,7 +30,9 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import com.android.systemui.statusbar.policy.NetworkController.WifiIndicators;
 import com.android.systemui.tests.R;
 
 import org.junit.Before;
@@ -86,28 +88,24 @@
         boolean out = true;
         String description = "Test";
         String secondaryLabel = "Secondary label";
-        mHandler.setWifiIndicators(enabled, status, qs, in, out, description, true, secondaryLabel);
+        WifiIndicators indicators = new WifiIndicators(
+                enabled, status, qs, in, out, description, true, secondaryLabel);
+        mHandler.setWifiIndicators(indicators);
         waitForCallbacks();
 
-        ArgumentCaptor<Boolean> enableArg = ArgumentCaptor.forClass(Boolean.class);
-        ArgumentCaptor<IconState> statusArg = ArgumentCaptor.forClass(IconState.class);
-        ArgumentCaptor<IconState> qsArg = ArgumentCaptor.forClass(IconState.class);
-        ArgumentCaptor<Boolean> inArg = ArgumentCaptor.forClass(Boolean.class);
-        ArgumentCaptor<Boolean> outArg = ArgumentCaptor.forClass(Boolean.class);
-        ArgumentCaptor<String> descArg = ArgumentCaptor.forClass(String.class);
-        ArgumentCaptor<Boolean> isTransient = ArgumentCaptor.forClass(Boolean.class);
-        ArgumentCaptor<String> secondary = ArgumentCaptor.forClass(String.class);
-        Mockito.verify(mSignalCallback).setWifiIndicators(enableArg.capture(),
-                statusArg.capture(), qsArg.capture(), inArg.capture(), outArg.capture(),
-                descArg.capture(), isTransient.capture(), secondary.capture());
-        assertEquals(enabled, (boolean) enableArg.getValue());
-        assertEquals(status, statusArg.getValue());
-        assertEquals(qs, qsArg.getValue());
-        assertEquals(in, (boolean) inArg.getValue());
-        assertEquals(out, (boolean) outArg.getValue());
-        assertEquals(description, descArg.getValue());
-        assertTrue(isTransient.getValue());
-        assertEquals(secondaryLabel, secondary.getValue());
+        ArgumentCaptor<WifiIndicators> indicatorArg =
+                ArgumentCaptor.forClass(WifiIndicators.class);
+        Mockito.verify(mSignalCallback).setWifiIndicators(indicatorArg.capture());
+        WifiIndicators expected = indicatorArg.getValue();
+
+        assertEquals(enabled, expected.enabled);
+        assertEquals(status, expected.statusIcon);
+        assertEquals(qs, expected.qsIcon);
+        assertEquals(in, expected.activityIn);
+        assertEquals(out, expected.activityOut);
+        assertEquals(description, expected.description);
+        assertTrue(expected.isTransient);
+        assertEquals(secondaryLabel, expected.statusLabel);
     }
 
     @Test
@@ -124,37 +122,30 @@
         boolean wide = true;
         int subId = 5;
         boolean roaming = true;
-        mHandler.setMobileDataIndicators(status, qs, type, qsType, in, out, typeDescription,
+        MobileDataIndicators indicators = new MobileDataIndicators(
+                status, qs, type, qsType, in, out, typeDescription,
                 typeDescriptionHtml, description, wide, subId, roaming, true);
+        mHandler.setMobileDataIndicators(indicators);
         waitForCallbacks();
 
-        ArgumentCaptor<IconState> statusArg = ArgumentCaptor.forClass(IconState.class);
-        ArgumentCaptor<IconState> qsArg = ArgumentCaptor.forClass(IconState.class);
-        ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class);
-        ArgumentCaptor<Integer> qsTypeIconArg = ArgumentCaptor.forClass(Integer.class);
-        ArgumentCaptor<Boolean> inArg = ArgumentCaptor.forClass(Boolean.class);
-        ArgumentCaptor<Boolean> outArg = ArgumentCaptor.forClass(Boolean.class);
-        ArgumentCaptor<CharSequence> typeContentArg = ArgumentCaptor.forClass(CharSequence.class);
-        ArgumentCaptor<CharSequence> typeContentHtmlArg =
-                ArgumentCaptor.forClass(CharSequence.class);
-        ArgumentCaptor<CharSequence> descArg = ArgumentCaptor.forClass(CharSequence.class);
-        ArgumentCaptor<Boolean> wideArg = ArgumentCaptor.forClass(Boolean.class);
-        ArgumentCaptor<Integer> subIdArg = ArgumentCaptor.forClass(Integer.class);
-        Mockito.verify(mSignalCallback).setMobileDataIndicators(statusArg.capture(),
-                qsArg.capture(), typeIconArg.capture(), qsTypeIconArg.capture(), inArg.capture(),
-                outArg.capture(), typeContentArg.capture(), typeContentHtmlArg.capture(),
-                descArg.capture(), wideArg.capture(), subIdArg.capture(), eq(roaming), eq(true));
-        assertEquals(status, statusArg.getValue());
-        assertEquals(qs, qsArg.getValue());
-        assertEquals(type, (int) typeIconArg.getValue());
-        assertEquals(qsType, (int) qsTypeIconArg.getValue());
-        assertEquals(in, (boolean) inArg.getValue());
-        assertEquals(out, (boolean) outArg.getValue());
-        assertEquals(typeDescription, typeContentArg.getValue());
-        assertEquals(typeDescriptionHtml, typeContentHtmlArg.getValue());
-        assertEquals(description, descArg.getValue());
-        assertEquals(wide, (boolean) wideArg.getValue());
-        assertEquals(subId, (int) subIdArg.getValue());
+        ArgumentCaptor<MobileDataIndicators> indicatorArg =
+                ArgumentCaptor.forClass(MobileDataIndicators.class);
+        Mockito.verify(mSignalCallback).setMobileDataIndicators(indicatorArg.capture());
+        MobileDataIndicators expected = indicatorArg.getValue();
+
+        assertEquals(status, expected.statusIcon);
+        assertEquals(qs, expected.qsIcon);
+        assertEquals(type, expected.statusType);
+        assertEquals(qsType, expected.qsType);
+        assertEquals(in, expected.activityIn);
+        assertEquals(out, expected.activityOut);
+        assertEquals(typeDescription, expected.typeContentDescription);
+        assertEquals(typeDescriptionHtml, expected.typeContentDescriptionHtml);
+        assertEquals(description, expected.description);
+        assertEquals(wide, expected.isWide);
+        assertEquals(subId, expected.subId);
+        assertTrue(expected.roaming);
+        assertTrue(expected.showTriangle);
     }
 
     @SuppressWarnings("unchecked")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 89cc2b5..b1b71cc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -21,9 +21,9 @@
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
 
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Matchers.isA;
@@ -76,6 +76,7 @@
 import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
 
 import org.junit.After;
@@ -173,8 +174,6 @@
         mMockSubDefaults = mock(SubscriptionDefaults.class);
         mNetCapabilities = new NetworkCapabilities();
         when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(true);
-        when(mMockCm.getDefaultNetworkCapabilitiesForUser(0)).thenReturn(
-                new NetworkCapabilities[] { mNetCapabilities });
         when(mMockTm.createForSubscriptionId(anyInt())).thenReturn(mMockTm);
         doAnswer(invocation -> {
             int rssi = invocation.getArgument(0);
@@ -257,8 +256,11 @@
             ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
         verify(mMockCm, atLeastOnce())
             .registerDefaultNetworkCallback(callbackArg.capture(), isA(Handler.class));
-        mDefaultCallbackInWifiTracker = callbackArg.getAllValues().get(0);
-        mDefaultCallbackInNetworkController = callbackArg.getAllValues().get(1);
+        int captureSize = callbackArg.getAllValues().size();
+        assertTrue(captureSize > 1);
+        assertEquals(captureSize % 2, 0);
+        mDefaultCallbackInWifiTracker = callbackArg.getAllValues().get(captureSize - 2);
+        mDefaultCallbackInNetworkController = callbackArg.getAllValues().get(captureSize - 1);
         assertNotNull(mDefaultCallbackInWifiTracker);
         assertNotNull(mDefaultCallbackInNetworkController);
         verify(mMockCm, atLeastOnce()).registerNetworkCallback(
@@ -307,14 +309,18 @@
         setLevel(DEFAULT_LEVEL);
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
                 TelephonyManager.NETWORK_TYPE_UMTS);
+        setConnectivityViaCallbackInNetworkController(
+                NetworkCapabilities.TRANSPORT_CELLULAR, true, true, null);
         setConnectivityViaBroadcast(
-            NetworkCapabilities.TRANSPORT_CELLULAR, true, true);
+                NetworkCapabilities.TRANSPORT_CELLULAR, true, true);
     }
 
     public void setConnectivityViaBroadcastForVcn(
             int networkType, boolean validated, boolean isConnected, VcnTransportInfo info) {
         mNetCapabilities.setTransportInfo(info);
         setConnectivityCommon(networkType, validated, isConnected);
+        mDefaultCallbackInNetworkController.onCapabilitiesChanged(
+                mock(Network.class), new NetworkCapabilities(mNetCapabilities));
         Intent i = new Intent(ConnectivityManager.INET_CONDITION_ACTION);
         mNetworkController.onReceive(mContext, i);
     }
@@ -322,6 +328,8 @@
     public void setConnectivityViaBroadcast(
         int networkType, boolean validated, boolean isConnected) {
         setConnectivityCommon(networkType, validated, isConnected);
+        mDefaultCallbackInNetworkController.onCapabilitiesChanged(
+                mock(Network.class), new NetworkCapabilities(mNetCapabilities));
         Intent i = new Intent(ConnectivityManager.INET_CONDITION_ACTION);
         mNetworkController.onReceive(mContext, i);
     }
@@ -364,6 +372,8 @@
                         new NetworkCapabilities(mNetCapabilities), new LinkProperties(), false);
                 mNetworkCallback.onCapabilitiesChanged(
                         mock(Network.class), new NetworkCapabilities(mNetCapabilities));
+                mDefaultCallbackInWifiTracker.onCapabilitiesChanged(
+                        mock(Network.class), new NetworkCapabilities(mNetCapabilities));
             } else {
                 mNetworkCallback.onLost(mock(Network.class));
             }
@@ -487,28 +497,21 @@
 
     protected void verifyLastQsMobileDataIndicators(boolean visible, int icon, int typeIcon,
             boolean dataIn, boolean dataOut) {
-        ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
-        ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class);
-        ArgumentCaptor<Boolean> dataInArg = ArgumentCaptor.forClass(Boolean.class);
-        ArgumentCaptor<Boolean> dataOutArg = ArgumentCaptor.forClass(Boolean.class);
+        ArgumentCaptor<MobileDataIndicators> indicatorsArg =
+                ArgumentCaptor.forClass(MobileDataIndicators.class);
 
         verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators(
-                    any(),
-                    iconArg.capture(),
-                    anyInt(),
-                    typeIconArg.capture(), dataInArg.capture(), dataOutArg.capture(),
-                    any(CharSequence.class), any(CharSequence.class), any(CharSequence.class),
-                    anyBoolean(), anyInt(), anyBoolean(), anyBoolean());
-        IconState iconState = iconArg.getValue();
+                    indicatorsArg.capture());
+        MobileDataIndicators expected = indicatorsArg.getValue();
         int state = SignalDrawable.getState(icon, CellSignalStrength.getNumSignalStrengthLevels(),
                 false);
-        assertEquals("Visibility in, quick settings", visible, iconState.visible);
-        assertEquals("Signal icon in, quick settings", state, iconState.icon);
-        assertEquals("Data icon in, quick settings", typeIcon, (int) typeIconArg.getValue());
+        assertEquals("Visibility in, quick settings", visible, expected.qsIcon.visible);
+        assertEquals("Signal icon in, quick settings", state, expected.qsIcon.icon);
+        assertEquals("Data icon in, quick settings", typeIcon, expected.qsType);
         assertEquals("Data direction in, in quick settings", dataIn,
-                (boolean) dataInArg.getValue());
+                expected.activityIn);
         assertEquals("Data direction out, in quick settings", dataOut,
-                (boolean) dataOutArg.getValue());
+                expected.activityOut);
     }
 
     protected void verifyLastMobileDataIndicators(boolean visible, int icon, int typeIcon) {
@@ -522,44 +525,35 @@
 
     protected void verifyLastMobileDataIndicators(boolean visible, int icon, int typeIcon,
         boolean roaming, boolean inet) {
-        ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
-        ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class);
+        ArgumentCaptor<MobileDataIndicators> indicatorsArg =
+                ArgumentCaptor.forClass(MobileDataIndicators.class);
 
         // TODO: Verify all fields.
         verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators(
-                iconArg.capture(),
-                any(),
-                typeIconArg.capture(),
-                anyInt(), anyBoolean(), anyBoolean(),
-                any(CharSequence.class), any(CharSequence.class), any(),
-                anyBoolean(), anyInt(), eq(roaming), anyBoolean());
-        IconState iconState = iconArg.getValue();
+                indicatorsArg.capture());
+        MobileDataIndicators expected = indicatorsArg.getValue();
         int state = icon == -1 ? 0
                 : SignalDrawable.getState(icon, CellSignalStrength.getNumSignalStrengthLevels(),
                         !inet);
-        assertEquals("Signal icon in status bar", state, iconState.icon);
-        assertEquals("Data icon in status bar", typeIcon, (int) typeIconArg.getValue());
-        assertEquals("Visibility in status bar", visible, iconState.visible);
+        assertEquals("Signal icon in status bar", state, expected.statusIcon.icon);
+        assertEquals("Data icon in status bar", typeIcon, expected.statusType);
+        assertEquals("Visibility in status bar", visible, expected.statusIcon.visible);
     }
 
     protected void verifyLastMobileDataIndicatorsForVcn(boolean visible, int level, int typeIcon,
             boolean inet) {
-        ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
-        ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class);
+        ArgumentCaptor<MobileDataIndicators> indicatorsArg =
+                ArgumentCaptor.forClass(MobileDataIndicators.class);
 
         verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators(
-                iconArg.capture(),
-                any(),
-                typeIconArg.capture(),
-                anyInt(), anyBoolean(), anyBoolean(),
-                any(CharSequence.class), any(CharSequence.class), any(),
-                anyBoolean(), anyInt(), anyBoolean(), anyBoolean());
-        IconState iconState = iconArg.getValue();
+                indicatorsArg.capture());
+
+        MobileDataIndicators expected = indicatorsArg.getValue();
         int state = SignalDrawable.getState(
                 level, CellSignalStrength.getNumSignalStrengthLevels(), !inet);
-        assertEquals("Signal icon in status bar", state, iconState.icon);
-        assertEquals("Data icon in status bar", typeIcon, (int) typeIconArg.getValue());
-        assertEquals("Visibility in status bar", visible, iconState.visible);
+        assertEquals("Signal icon in status bar", state, expected.statusIcon.icon);
+        assertEquals("Data icon in status bar", typeIcon, expected.statusType);
+        assertEquals("Visibility in status bar", visible, expected.statusIcon.visible);
     }
 
     protected void verifyLastMobileDataIndicators(boolean visible, int icon, int typeIcon,
@@ -580,6 +574,8 @@
             boolean qsVisible, int qsIcon, int qsTypeIcon, boolean dataIn, boolean dataOut,
             boolean cutOut, CharSequence typeContentDescription,
             CharSequence typeContentDescriptionHtml) {
+        ArgumentCaptor<MobileDataIndicators> indicatorsArg =
+                ArgumentCaptor.forClass(MobileDataIndicators.class);
         ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
         ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class);
         ArgumentCaptor<IconState> qsIconArg = ArgumentCaptor.forClass(IconState.class);
@@ -592,17 +588,9 @@
                 ArgumentCaptor.forClass(CharSequence.class);
 
         verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators(
-                iconArg.capture(),
-                qsIconArg.capture(),
-                typeIconArg.capture(),
-                qsTypeIconArg.capture(),
-                dataInArg.capture(),
-                dataOutArg.capture(),
-                typeContentDescriptionArg.capture(),
-                typeContentDescriptionHtmlArg.capture(),
-                any(), anyBoolean(), anyInt(), anyBoolean(), anyBoolean());
+                indicatorsArg.capture());
 
-        IconState iconState = iconArg.getValue();
+        MobileDataIndicators expected = indicatorsArg.getValue();
 
         int numSignalStrengthBins = CellSignalStrength.getNumSignalStrengthLevels();
         if (mMobileSignalController.mInflateSignalStrengths) {
@@ -610,29 +598,28 @@
             icon++;
         }
         int state = SignalDrawable.getState(icon, numSignalStrengthBins, cutOut);
-        assertEquals("Data icon in status bar", typeIcon, (int) typeIconArg.getValue());
-        assertEquals("Signal icon in status bar", state, iconState.icon);
-        assertEquals("Visibility in status bar", visible, iconState.visible);
+        assertEquals("Data icon in status bar", typeIcon, expected.statusType);
+        assertEquals("Signal icon in status bar", state, expected.statusIcon.icon);
+        assertEquals("Visibility in status bar", visible, expected.statusIcon.visible);
 
-        iconState = qsIconArg.getValue();
         if (visible) {
-            assertEquals("Visibility in quick settings", qsVisible, iconState.visible);
-            assertEquals("Signal icon in quick settings", state, iconState.icon);
+            assertEquals("Visibility in quick settings", qsVisible, expected.qsIcon.visible);
+            assertEquals("Signal icon in quick settings", state, expected.qsIcon.icon);
         } else {
-            assertEquals("Cellular is not default", null, iconState);
+            assertEquals("Cellular is not default", null, expected.qsIcon);
         }
-        assertEquals("Data icon in quick settings", qsTypeIcon, (int) qsTypeIconArg.getValue());
+        assertEquals("Data icon in quick settings", qsTypeIcon, expected.qsType);
         assertEquals("Data direction in in quick settings", dataIn,
-                (boolean) dataInArg.getValue());
+                expected.activityIn);
         assertEquals("Data direction out in quick settings", dataOut,
-                (boolean) dataOutArg.getValue());
+                expected.activityOut);
         if (typeContentDescription != null) { // Only check if it was provided
             assertEquals("Type content description", typeContentDescription,
-                    typeContentDescriptionArg.getValue());
+                    expected.typeContentDescription);
         }
         if (typeContentDescriptionHtml != null) { // Only check if it was provided
             assertEquals("Type content description (html)", typeContentDescriptionHtml,
-                    typeContentDescriptionHtmlArg.getValue());
+                    expected.typeContentDescriptionHtml);
         }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
index fc1a08ac..847030e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
@@ -3,7 +3,6 @@
 import static junit.framework.Assert.assertEquals;
 
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -21,7 +20,7 @@
 import android.testing.TestableLooper.RunWithLooper;
 
 import com.android.settingslib.mobile.TelephonyIcons;
-import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.WifiIndicators;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -224,13 +223,14 @@
         setWifiEnabled(true);
         verifyLastWifiIcon(false, WifiIcons.WIFI_NO_NETWORK);
 
+        mNetworkController.setNoNetworksAvailable(false);
         setWifiStateForVcn(true, testSsid);
         setWifiLevelForVcn(0);
-
         // Connected, but still not validated - does not show
         //verifyLastWifiIcon(false, WifiIcons.WIFI_SIGNAL_STRENGTH[0][0]);
-        verifyLastMobileDataIndicatorsForVcn(false, 0, TelephonyIcons.ICON_CWF, false);
+        verifyLastMobileDataIndicatorsForVcn(false, 0, 0, false);
 
+        mNetworkController.setNoNetworksAvailable(true);
         for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) {
             setWifiLevelForVcn(testLevel);
 
@@ -240,7 +240,7 @@
 
             setConnectivityViaBroadcastForVcn(
                     NetworkCapabilities.TRANSPORT_CELLULAR, false, true, mVcnTransportInfo);
-            verifyLastMobileDataIndicatorsForVcn(false, testLevel, TelephonyIcons.ICON_CWF, false);
+            verifyLastMobileDataIndicatorsForVcn(true, testLevel, TelephonyIcons.ICON_CWF, false);
         }
     }
 
@@ -316,44 +316,42 @@
     }
 
     protected void verifyLastQsDataDirection(boolean in, boolean out) {
-        ArgumentCaptor<Boolean> inArg = ArgumentCaptor.forClass(Boolean.class);
-        ArgumentCaptor<Boolean> outArg = ArgumentCaptor.forClass(Boolean.class);
+        ArgumentCaptor<WifiIndicators> indicatorsArg =
+                ArgumentCaptor.forClass(WifiIndicators.class);
 
         Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators(
-                anyBoolean(), any(), any(), inArg.capture(), outArg.capture(), any(), anyBoolean(),
-                any());
-        assertEquals("WiFi data in, in quick settings", in, (boolean) inArg.getValue());
-        assertEquals("WiFi data out, in quick settings", out, (boolean) outArg.getValue());
+                indicatorsArg.capture());
+        WifiIndicators expected = indicatorsArg.getValue();
+        assertEquals("WiFi data in, in quick settings", in, expected.activityIn);
+        assertEquals("WiFi data out, in quick settings", out, expected.activityOut);
     }
 
     protected void verifyLastQsWifiIcon(boolean enabled, boolean connected, int icon,
             String description) {
-        ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
-        ArgumentCaptor<Boolean> enabledArg = ArgumentCaptor.forClass(Boolean.class);
-        ArgumentCaptor<String> descArg = ArgumentCaptor.forClass(String.class);
+        ArgumentCaptor<WifiIndicators> indicatorsArg =
+                ArgumentCaptor.forClass(WifiIndicators.class);
 
         Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators(
-                enabledArg.capture(), any(), iconArg.capture(), anyBoolean(),
-                anyBoolean(), descArg.capture(), anyBoolean(), any());
-        IconState iconState = iconArg.getValue();
-        assertEquals("WiFi enabled, in quick settings", enabled, (boolean) enabledArg.getValue());
-        assertEquals("WiFI desc (ssid), in quick settings", description, descArg.getValue());
+                indicatorsArg.capture());
+        WifiIndicators expected = indicatorsArg.getValue();
+        assertEquals("WiFi enabled, in quick settings", enabled, expected.enabled);
+        assertEquals("WiFI desc (ssid), in quick settings", description, expected.description);
         if (enabled && connected) {
-            assertEquals("WiFi connected, in quick settings", connected, iconState.visible);
-            assertEquals("WiFi signal, in quick settings", icon, iconState.icon);
+            assertEquals("WiFi connected, in quick settings", connected, expected.qsIcon.visible);
+            assertEquals("WiFi signal, in quick settings", icon, expected.qsIcon.icon);
         } else {
-            assertEquals("WiFi is not default", null, iconState);
+            assertEquals("WiFi is not default", null, expected.qsIcon);
         }
     }
 
     protected void verifyLastWifiIcon(boolean visible, int icon) {
-        ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
+        ArgumentCaptor<WifiIndicators> indicatorsArg =
+                ArgumentCaptor.forClass(WifiIndicators.class);
 
         Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators(
-                anyBoolean(), iconArg.capture(), any(), anyBoolean(), anyBoolean(),
-                any(), anyBoolean(), any());
-        IconState iconState = iconArg.getValue();
-        assertEquals("WiFi visible, in status bar", visible, iconState.visible);
-        assertEquals("WiFi signal, in status bar", icon, iconState.icon);
+                indicatorsArg.capture());
+        WifiIndicators expected = indicatorsArg.getValue();
+        assertEquals("WiFi visible, in status bar", visible, expected.statusIcon.visible);
+        assertEquals("WiFi signal, in status bar", icon, expected.statusIcon.icon);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
index 45828c3..6067b42 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
@@ -23,6 +23,7 @@
 import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ICON_SETTINGS;
 import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ICON_SYSUI;
 import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ICON_THEME_PICKER;
+import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_NEUTRAL_PALETTE;
 import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_SHAPE;
 import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_SYSTEM_PALETTE;
 import static com.android.systemui.theme.ThemeOverlayApplier.SETTINGS_PACKAGE;
@@ -31,7 +32,6 @@
 import static com.android.systemui.theme.ThemeOverlayApplier.THEME_CATEGORIES;
 
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.mock;
@@ -87,7 +87,9 @@
     private static final String THEMEPICKER_PACKAGE = "com.android.wallpaper";
     private static final String LAUNCHER_PACKAGE = "com.android.launcher3";
     private static final UserHandle TEST_USER = UserHandle.of(5);
-    private static final Set<UserHandle> TEST_USER_HANDLES = Sets.newHashSet(TEST_USER);
+    private static final UserHandle TEST_USER_MANAGED_PROFILE = UserHandle.of(6);
+    private static final Set<UserHandle> TEST_USER_HANDLES =
+            Sets.newHashSet(TEST_USER_MANAGED_PROFILE);
 
     @Mock
     OverlayManager mOverlayManager;
@@ -114,6 +116,8 @@
                                 ANDROID_PACKAGE, OVERLAY_CATEGORY_ACCENT_COLOR, false),
                         createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_SYSTEM_PALETTE,
                                 ANDROID_PACKAGE, OVERLAY_CATEGORY_SYSTEM_PALETTE, false),
+                        createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_NEUTRAL_PALETTE,
+                                ANDROID_PACKAGE, OVERLAY_CATEGORY_NEUTRAL_PALETTE, false),
                         createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_FONT,
                                 ANDROID_PACKAGE, OVERLAY_CATEGORY_FONT, false),
                         createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_SHAPE,
@@ -124,6 +128,8 @@
                                 ANDROID_PACKAGE, OVERLAY_CATEGORY_ACCENT_COLOR, true),
                         createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_SYSTEM_PALETTE,
                                 ANDROID_PACKAGE, OVERLAY_CATEGORY_SYSTEM_PALETTE, true),
+                        createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_NEUTRAL_PALETTE,
+                                ANDROID_PACKAGE, OVERLAY_CATEGORY_NEUTRAL_PALETTE, true),
                         createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_FONT,
                                 ANDROID_PACKAGE, OVERLAY_CATEGORY_FONT, true),
                         createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_SHAPE,
@@ -154,13 +160,19 @@
                                 THEMEPICKER_PACKAGE, OVERLAY_CATEGORY_ICON_THEME_PICKER, false),
                         createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ICON_THEME_PICKER,
                                 THEMEPICKER_PACKAGE, OVERLAY_CATEGORY_ICON_THEME_PICKER, true)));
+
+        OverlayInfo launcherTargetInfo = new OverlayInfo("packageName", LAUNCHER_PACKAGE,
+                null, null, "/", 0, 0, 0, false);
+        when(mOverlayManager.getOverlayInfo(any(OverlayIdentifier.class), any()))
+                .thenReturn(launcherTargetInfo);
         clearInvocations(mOverlayManager);
         verify(mDumpManager).registerDumpable(any(), any());
     }
 
     @Test
     public void allCategoriesSpecified_allEnabledExclusively() {
-        mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER_HANDLES);
+        mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(),
+                TEST_USER_HANDLES);
         verify(mOverlayManager).commit(any());
 
         for (OverlayIdentifier overlayPackage : ALL_CATEGORIES_MAP.values()) {
@@ -171,7 +183,8 @@
 
     @Test
     public void allCategoriesSpecified_sysuiCategoriesAlsoAppliedToSysuiUser() {
-        mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER_HANDLES);
+        mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(),
+                TEST_USER_HANDLES);
 
         for (Map.Entry<String, OverlayIdentifier> entry : ALL_CATEGORIES_MAP.entrySet()) {
             if (SYSTEM_USER_CATEGORIES.contains(entry.getKey())) {
@@ -187,27 +200,25 @@
     @Test
     public void allCategoriesSpecified_enabledForAllUserHandles() {
         Set<UserHandle> userHandles = Sets.newHashSet(TEST_USER_HANDLES);
-        UserHandle newUserHandle = UserHandle.of(10);
-        userHandles.add(newUserHandle);
-        mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, userHandles);
+        mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(),
+                userHandles);
 
         for (OverlayIdentifier overlayPackage : ALL_CATEGORIES_MAP.values()) {
             verify(mTransactionBuilder).setEnabled(eq(overlayPackage), eq(true),
                     eq(TEST_USER.getIdentifier()));
-            verify(mTransactionBuilder).setEnabled(eq(overlayPackage), eq(true),
-                    eq(newUserHandle.getIdentifier()));
+            // Not enabled for work profile because the target package is LAUNCHER_PACKAGE
+            verify(mTransactionBuilder, never()).setEnabled(eq(overlayPackage), eq(true),
+                    eq(TEST_USER_MANAGED_PROFILE.getIdentifier()));
         }
     }
 
     @Test
     public void applyCurrentUserOverlays_createsPendingOverlays() {
-        Set<UserHandle> userHandles = Sets.newHashSet(TEST_USER_HANDLES);
-        UserHandle newUserHandle = UserHandle.of(10);
-        userHandles.add(newUserHandle);
-        FabricatedOverlay[] pendingCreation = new FabricatedOverlay[] {
+        FabricatedOverlay[] pendingCreation = new FabricatedOverlay[]{
                 mock(FabricatedOverlay.class)
         };
-        mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, pendingCreation, userHandles);
+        mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, pendingCreation,
+                TEST_USER.getIdentifier(), TEST_USER_HANDLES);
 
         for (FabricatedOverlay overlay : pendingCreation) {
             verify(mTransactionBuilder).registerFabricatedOverlay(eq(overlay));
@@ -215,20 +226,13 @@
     }
 
     @Test
-    public void allCategoriesSpecified_overlayManagerNotQueried() {
-        mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER_HANDLES);
-
-        verify(mOverlayManager, never())
-                .getOverlayInfosForTarget(anyString(), any(UserHandle.class));
-    }
-
-    @Test
     public void someCategoriesSpecified_specifiedEnabled_unspecifiedDisabled() {
         Map<String, OverlayIdentifier> categoryToPackage = new HashMap<>(ALL_CATEGORIES_MAP);
         categoryToPackage.remove(OVERLAY_CATEGORY_ICON_SETTINGS);
         categoryToPackage.remove(OVERLAY_CATEGORY_ICON_ANDROID);
 
-        mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER_HANDLES);
+        mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER.getIdentifier(),
+                TEST_USER_HANDLES);
 
         for (OverlayIdentifier overlayPackage : categoryToPackage.values()) {
             verify(mTransactionBuilder).setEnabled(eq(overlayPackage), eq(true),
@@ -244,7 +248,8 @@
 
     @Test
     public void zeroCategoriesSpecified_allDisabled() {
-        mManager.applyCurrentUserOverlays(Maps.newArrayMap(), null, TEST_USER_HANDLES);
+        mManager.applyCurrentUserOverlays(Maps.newArrayMap(), null, TEST_USER.getIdentifier(),
+                TEST_USER_HANDLES);
 
         for (String category : THEME_CATEGORIES) {
             verify(mTransactionBuilder).setEnabled(
@@ -258,7 +263,8 @@
         Map<String, OverlayIdentifier> categoryToPackage = new HashMap<>(ALL_CATEGORIES_MAP);
         categoryToPackage.put("blah.category", new OverlayIdentifier("com.example.blah.category"));
 
-        mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER_HANDLES);
+        mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER.getIdentifier(),
+                TEST_USER_HANDLES);
 
         verify(mTransactionBuilder, never()).setEnabled(
                 eq(new OverlayIdentifier("com.example.blah.category")), eq(false),
@@ -268,23 +274,6 @@
                 eq(TEST_USER.getIdentifier()));
     }
 
-    @Test
-    public void overlayManagerOnlyQueriedForUnspecifiedPackages() {
-        Map<String, OverlayIdentifier> categoryToPackage = new HashMap<>(ALL_CATEGORIES_MAP);
-        categoryToPackage.remove(OVERLAY_CATEGORY_ICON_SETTINGS);
-
-        mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER_HANDLES);
-
-        verify(mOverlayManager).getOverlayInfosForTarget(SETTINGS_PACKAGE, UserHandle.SYSTEM);
-        verify(mOverlayManager, never()).getOverlayInfosForTarget(ANDROID_PACKAGE,
-                UserHandle.SYSTEM);
-        verify(mOverlayManager, never()).getOverlayInfosForTarget(SYSUI_PACKAGE, UserHandle.SYSTEM);
-        verify(mOverlayManager, never()).getOverlayInfosForTarget(LAUNCHER_PACKAGE,
-                UserHandle.SYSTEM);
-        verify(mOverlayManager, never()).getOverlayInfosForTarget(THEMEPICKER_PACKAGE,
-                UserHandle.SYSTEM);
-    }
-
     private static OverlayInfo createOverlayInfo(String packageName, String targetPackageName,
             String category, boolean enabled) {
         return new OverlayInfo(packageName, null, targetPackageName, null, category, "",
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index aa385ef..8a0ac11 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -19,13 +19,13 @@
 import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ACCENT_COLOR;
 import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_NEUTRAL_PALETTE;
 import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_SYSTEM_PALETTE;
-import static com.android.systemui.theme.ThemeOverlayController.USE_LOCK_SCREEN_WALLPAPER;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -33,6 +33,8 @@
 
 import android.app.WallpaperColors;
 import android.app.WallpaperManager;
+import android.content.BroadcastReceiver;
+import android.content.Intent;
 import android.content.om.FabricatedOverlay;
 import android.content.om.OverlayIdentifier;
 import android.graphics.Color;
@@ -91,7 +93,7 @@
     @Mock
     private FeatureFlags mFeatureFlags;
     @Captor
-    private ArgumentCaptor<KeyguardStateController.Callback> mKeyguardStateControllerCallback;
+    private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiver;
     @Captor
     private ArgumentCaptor<WallpaperManager.OnColorsChangedListener> mColorsListener;
 
@@ -114,12 +116,10 @@
         };
 
         mThemeOverlayController.start();
-        if (USE_LOCK_SCREEN_WALLPAPER) {
-            verify(mKeyguardStateController).addCallback(
-                    mKeyguardStateControllerCallback.capture());
-        }
         verify(mWallpaperManager).addOnColorsChangedListener(mColorsListener.capture(), eq(null),
                 eq(UserHandle.USER_ALL));
+        verify(mBroadcastDispatcher).registerReceiver(mBroadcastReceiver.capture(), any(),
+                eq(mMainExecutor), any());
         verify(mDumpManager).registerDumpable(any(), any());
     }
 
@@ -129,7 +129,6 @@
         verify(mBgExecutor).execute(registrationRunnable.capture());
 
         registrationRunnable.getValue().run();
-        verify(mWallpaperManager).getWallpaperColors(eq(WallpaperManager.FLAG_LOCK));
         verify(mWallpaperManager).getWallpaperColors(eq(WallpaperManager.FLAG_SYSTEM));
     }
 
@@ -143,7 +142,7 @@
                 ArgumentCaptor.forClass(Map.class);
 
         verify(mThemeOverlayApplier)
-                .applyCurrentUserOverlays(themeOverlays.capture(), any(), any());
+                .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any());
 
         // Assert that we received the colors that we were expecting
         assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
@@ -156,6 +155,18 @@
         // Should not ask again if changed to same value
         mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
         verifyNoMoreInteractions(mThemeOverlayApplier);
+
+        // Should not ask again even for new colors until we change wallpapers
+        mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.BLACK),
+                null, null), WallpaperManager.FLAG_SYSTEM);
+        verifyNoMoreInteractions(mThemeOverlayApplier);
+
+        // But should change theme after changing wallpapers
+        clearInvocations(mThemeOverlayApplier);
+        mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_WALLPAPER_CHANGED));
+        mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.BLACK),
+                null, null), WallpaperManager.FLAG_SYSTEM);
+        verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
     }
 
     @Test
@@ -175,7 +186,7 @@
                 ArgumentCaptor.forClass(Map.class);
 
         verify(mThemeOverlayApplier)
-                .applyCurrentUserOverlays(themeOverlays.capture(), any(), any());
+                .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any());
 
         // Assert that we received the colors that we were expecting
         assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
@@ -198,7 +209,7 @@
                 ArgumentCaptor.forClass(Map.class);
 
         verify(mThemeOverlayApplier)
-                .applyCurrentUserOverlays(themeOverlays.capture(), any(), any());
+                .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any());
 
         // Assert that we received the colors that we were expecting
         assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index c085689..3cea175 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -22,6 +22,7 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.app.KeyguardManager;
@@ -37,6 +38,8 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.Prefs;
+import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.VolumeDialogController;
 import com.android.systemui.plugins.VolumeDialogController.State;
@@ -58,6 +61,11 @@
 public class VolumeDialogImplTest extends SysuiTestCase {
 
     VolumeDialogImpl mDialog;
+    View mActiveRinger;
+    View mDrawerContainer;
+    View mDrawerVibrate;
+    View mDrawerMute;
+    View mDrawerNormal;
 
     @Mock
     VolumeDialogController mController;
@@ -80,6 +88,17 @@
         mDialog.init(0, null);
         State state = createShellState();
         mDialog.onStateChangedH(state);
+
+        mActiveRinger = mDialog.getDialogView().findViewById(
+                R.id.volume_new_ringer_active_icon_container);
+        mDrawerContainer = mDialog.getDialogView().findViewById(R.id.volume_drawer_container);
+        mDrawerVibrate = mDrawerContainer.findViewById(R.id.volume_drawer_vibrate);
+        mDrawerMute = mDrawerContainer.findViewById(R.id.volume_drawer_mute);
+        mDrawerNormal = mDrawerContainer.findViewById(R.id.volume_drawer_normal);
+
+        Prefs.putInt(mContext,
+                Prefs.Key.SEEN_RINGER_GUIDANCE_COUNT,
+                VolumePrefs.SHOW_RINGER_TOAST_COUNT + 1);
     }
 
     private State createShellState() {
@@ -207,6 +226,48 @@
         verify(mController, never()).vibrate(any());
     }
 
+    @Test
+    public void testSelectVibrateFromDrawer() {
+        final State initialUnsetState = new State();
+        initialUnsetState.ringerModeInternal = AudioManager.RINGER_MODE_NORMAL;
+        mDialog.onStateChangedH(initialUnsetState);
+
+        mActiveRinger.performClick();
+        mDrawerVibrate.performClick();
+
+        // Make sure we've actually changed the ringer mode.
+        verify(mController, times(1)).setRingerMode(
+                AudioManager.RINGER_MODE_VIBRATE, false);
+    }
+
+    @Test
+    public void testSelectMuteFromDrawer() {
+        final State initialUnsetState = new State();
+        initialUnsetState.ringerModeInternal = AudioManager.RINGER_MODE_NORMAL;
+        mDialog.onStateChangedH(initialUnsetState);
+
+        mActiveRinger.performClick();
+        mDrawerMute.performClick();
+
+        // Make sure we've actually changed the ringer mode.
+        verify(mController, times(1)).setRingerMode(
+                AudioManager.RINGER_MODE_SILENT, false);
+    }
+
+    @Test
+    public void testSelectNormalFromDrawer() {
+        final State initialUnsetState = new State();
+        initialUnsetState.ringerModeInternal = AudioManager.RINGER_MODE_VIBRATE;
+        mDialog.onStateChangedH(initialUnsetState);
+
+        mActiveRinger.performClick();
+        mDrawerNormal.performClick();
+
+        // Make sure we've actually changed the ringer mode.
+        verify(mController, times(1)).setRingerMode(
+                AudioManager.RINGER_MODE_NORMAL, false);
+    }
+
 /*
     @Test
     public void testContentDescriptions() {
diff --git a/packages/overlays/AccentColorAmethystOverlay/Android.bp b/packages/overlays/AccentColorAmethystOverlay/Android.bp
index 7519b12..186d770 100644
--- a/packages/overlays/AccentColorAmethystOverlay/Android.bp
+++ b/packages/overlays/AccentColorAmethystOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "AccentColorAmethystOverlay",
     theme: "AccentColorAmethyst",
diff --git a/packages/overlays/AccentColorAquamarineOverlay/Android.bp b/packages/overlays/AccentColorAquamarineOverlay/Android.bp
index 4469b36..7fd64f3 100644
--- a/packages/overlays/AccentColorAquamarineOverlay/Android.bp
+++ b/packages/overlays/AccentColorAquamarineOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "AccentColorAquamarineOverlay",
     theme: "AccentColorAquamarine",
diff --git a/packages/overlays/AccentColorBlackOverlay/Android.bp b/packages/overlays/AccentColorBlackOverlay/Android.bp
index bfee26e..ac923eb 100644
--- a/packages/overlays/AccentColorBlackOverlay/Android.bp
+++ b/packages/overlays/AccentColorBlackOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "AccentColorBlackOverlay",
     theme: "AccentColorBlack",
diff --git a/packages/overlays/AccentColorCarbonOverlay/Android.bp b/packages/overlays/AccentColorCarbonOverlay/Android.bp
index 47f66dd..f4f1b8b 100644
--- a/packages/overlays/AccentColorCarbonOverlay/Android.bp
+++ b/packages/overlays/AccentColorCarbonOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "AccentColorCarbonOverlay",
     theme: "AccentColorCarbon",
diff --git a/packages/overlays/AccentColorCinnamonOverlay/Android.bp b/packages/overlays/AccentColorCinnamonOverlay/Android.bp
index 8250315..53899bf 100644
--- a/packages/overlays/AccentColorCinnamonOverlay/Android.bp
+++ b/packages/overlays/AccentColorCinnamonOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "AccentColorCinnamonOverlay",
     theme: "AccentColorCinnamon",
diff --git a/packages/overlays/AccentColorGreenOverlay/Android.bp b/packages/overlays/AccentColorGreenOverlay/Android.bp
index 15b50c7..5b1f744 100644
--- a/packages/overlays/AccentColorGreenOverlay/Android.bp
+++ b/packages/overlays/AccentColorGreenOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "AccentColorGreenOverlay",
     theme: "AccentColorGreen",
diff --git a/packages/overlays/AccentColorOceanOverlay/Android.bp b/packages/overlays/AccentColorOceanOverlay/Android.bp
index 6ad63bc..a8588304 100644
--- a/packages/overlays/AccentColorOceanOverlay/Android.bp
+++ b/packages/overlays/AccentColorOceanOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "AccentColorOceanOverlay",
     theme: "AccentColorOcean",
diff --git a/packages/overlays/AccentColorOrchidOverlay/Android.bp b/packages/overlays/AccentColorOrchidOverlay/Android.bp
index b669333..31ed309 100644
--- a/packages/overlays/AccentColorOrchidOverlay/Android.bp
+++ b/packages/overlays/AccentColorOrchidOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "AccentColorOrchidOverlay",
     theme: "AccentColorOrchid",
diff --git a/packages/overlays/AccentColorPaletteOverlay/Android.bp b/packages/overlays/AccentColorPaletteOverlay/Android.bp
index eeefd16..a6cc1de 100644
--- a/packages/overlays/AccentColorPaletteOverlay/Android.bp
+++ b/packages/overlays/AccentColorPaletteOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "AccentColorPaletteOverlay",
     theme: "AccentColorPalette",
diff --git a/packages/overlays/AccentColorPurpleOverlay/Android.bp b/packages/overlays/AccentColorPurpleOverlay/Android.bp
index ead95df..80e0ab1 100644
--- a/packages/overlays/AccentColorPurpleOverlay/Android.bp
+++ b/packages/overlays/AccentColorPurpleOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "AccentColorPurpleOverlay",
     theme: "AccentColorPurple",
diff --git a/packages/overlays/AccentColorSandOverlay/Android.bp b/packages/overlays/AccentColorSandOverlay/Android.bp
index f70578a..771abca 100644
--- a/packages/overlays/AccentColorSandOverlay/Android.bp
+++ b/packages/overlays/AccentColorSandOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "AccentColorSandOverlay",
     theme: "AccentColorSand",
diff --git a/packages/overlays/AccentColorSpaceOverlay/Android.bp b/packages/overlays/AccentColorSpaceOverlay/Android.bp
index 1d713df..8e4abac 100644
--- a/packages/overlays/AccentColorSpaceOverlay/Android.bp
+++ b/packages/overlays/AccentColorSpaceOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "AccentColorSpaceOverlay",
     theme: "AccentColorSpace",
diff --git a/packages/overlays/AccentColorTangerineOverlay/Android.bp b/packages/overlays/AccentColorTangerineOverlay/Android.bp
index d3b1e54..75c708e 100644
--- a/packages/overlays/AccentColorTangerineOverlay/Android.bp
+++ b/packages/overlays/AccentColorTangerineOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "AccentColorTangerineOverlay",
     theme: "AccentColorTangerine",
diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/Android.bp b/packages/overlays/DisplayCutoutEmulationCornerOverlay/Android.bp
index b8def987..8e03809 100644
--- a/packages/overlays/DisplayCutoutEmulationCornerOverlay/Android.bp
+++ b/packages/overlays/DisplayCutoutEmulationCornerOverlay/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
 runtime_resource_overlay {
     name: "DisplayCutoutEmulationCornerOverlay",
     theme: "DisplayCutoutEmulationCorner",
diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.bp b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.bp
index b64ddfd..afa5b64 100644
--- a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.bp
+++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
 runtime_resource_overlay {
     name: "DisplayCutoutEmulationDoubleOverlay",
     theme: "DisplayCutoutEmulationDouble",
diff --git a/packages/overlays/DisplayCutoutEmulationHoleOverlay/Android.bp b/packages/overlays/DisplayCutoutEmulationHoleOverlay/Android.bp
index 86cfebf..eae907d 100644
--- a/packages/overlays/DisplayCutoutEmulationHoleOverlay/Android.bp
+++ b/packages/overlays/DisplayCutoutEmulationHoleOverlay/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
 runtime_resource_overlay {
     name: "DisplayCutoutEmulationHoleOverlay",
     theme: "DisplayCutoutEmulationHole",
diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.bp b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.bp
index 28ad9db..25bc676 100644
--- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.bp
+++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
 runtime_resource_overlay {
     name: "DisplayCutoutEmulationNarrowOverlay",
     theme: "DisplayCutoutEmulationNarrow",
diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/Android.bp b/packages/overlays/DisplayCutoutEmulationTallOverlay/Android.bp
index cd00386..2828612 100644
--- a/packages/overlays/DisplayCutoutEmulationTallOverlay/Android.bp
+++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
 runtime_resource_overlay {
     name: "DisplayCutoutEmulationTallOverlay",
     theme: "DisplayCutoutEmulationTall",
diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/Android.bp b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/Android.bp
index d5fe683..66be777 100644
--- a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/Android.bp
+++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
 runtime_resource_overlay {
     name: "DisplayCutoutEmulationWaterfallOverlay",
     theme: "DisplayCutoutEmulationWaterfall",
diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/Android.bp b/packages/overlays/DisplayCutoutEmulationWideOverlay/Android.bp
index 0157ec4..e71cefe 100644
--- a/packages/overlays/DisplayCutoutEmulationWideOverlay/Android.bp
+++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
 runtime_resource_overlay {
     name: "DisplayCutoutEmulationWideOverlay",
     theme: "DisplayCutoutEmulationWide",
diff --git a/packages/overlays/FontNotoSerifSourceOverlay/Android.bp b/packages/overlays/FontNotoSerifSourceOverlay/Android.bp
index 7fd145b..231295b 100644
--- a/packages/overlays/FontNotoSerifSourceOverlay/Android.bp
+++ b/packages/overlays/FontNotoSerifSourceOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "FontNotoSerifSourceOverlay",
     theme: "FontNotoSerifSource",
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/Android.bp b/packages/overlays/IconPackCircularAndroidOverlay/Android.bp
index cd5829a..7040358 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/Android.bp
+++ b/packages/overlays/IconPackCircularAndroidOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackCircularAndroidOverlay",
     theme: "IconPackCircularAndroid",
diff --git a/packages/overlays/IconPackCircularLauncherOverlay/Android.bp b/packages/overlays/IconPackCircularLauncherOverlay/Android.bp
index 5f2491d..4f8b663 100644
--- a/packages/overlays/IconPackCircularLauncherOverlay/Android.bp
+++ b/packages/overlays/IconPackCircularLauncherOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackCircularLauncherOverlay",
     theme: "IconPackCircularLauncher",
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/Android.bp b/packages/overlays/IconPackCircularSettingsOverlay/Android.bp
index d7bc657..93220c8 100644
--- a/packages/overlays/IconPackCircularSettingsOverlay/Android.bp
+++ b/packages/overlays/IconPackCircularSettingsOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackCircularSettingsOverlay",
     theme: "IconPackCircularSettings",
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/Android.bp b/packages/overlays/IconPackCircularSystemUIOverlay/Android.bp
index 73b8cd8..4eaa420 100644
--- a/packages/overlays/IconPackCircularSystemUIOverlay/Android.bp
+++ b/packages/overlays/IconPackCircularSystemUIOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackCircularSystemUIOverlay",
     theme: "IconPackCircularSystemUI",
diff --git a/packages/overlays/IconPackCircularThemePickerOverlay/Android.bp b/packages/overlays/IconPackCircularThemePickerOverlay/Android.bp
index 5063932..5105b79 100644
--- a/packages/overlays/IconPackCircularThemePickerOverlay/Android.bp
+++ b/packages/overlays/IconPackCircularThemePickerOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackCircularThemePickerOverlay",
     theme: "IconPackCircularThemePicker",
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/Android.bp b/packages/overlays/IconPackFilledAndroidOverlay/Android.bp
index 83f3656..3c4025d 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/Android.bp
+++ b/packages/overlays/IconPackFilledAndroidOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackFilledAndroidOverlay",
     theme: "IconPackFilledAndroid",
diff --git a/packages/overlays/IconPackFilledLauncherOverlay/Android.bp b/packages/overlays/IconPackFilledLauncherOverlay/Android.bp
index 6ca2566..3c5078c 100644
--- a/packages/overlays/IconPackFilledLauncherOverlay/Android.bp
+++ b/packages/overlays/IconPackFilledLauncherOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackFilledLauncherOverlay",
     theme: "IconPackFilledLauncher",
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/Android.bp b/packages/overlays/IconPackFilledSettingsOverlay/Android.bp
index 8551bd5..b5148c2 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/Android.bp
+++ b/packages/overlays/IconPackFilledSettingsOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackFilledSettingsOverlay",
     theme: "IconPackFilledSettings",
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/Android.bp b/packages/overlays/IconPackFilledSystemUIOverlay/Android.bp
index 684deb4..eb040a5 100644
--- a/packages/overlays/IconPackFilledSystemUIOverlay/Android.bp
+++ b/packages/overlays/IconPackFilledSystemUIOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackFilledSystemUIOverlay",
     theme: "IconPackFilledSystemUI",
diff --git a/packages/overlays/IconPackFilledThemePickerOverlay/Android.bp b/packages/overlays/IconPackFilledThemePickerOverlay/Android.bp
index dae378f..bee4808 100644
--- a/packages/overlays/IconPackFilledThemePickerOverlay/Android.bp
+++ b/packages/overlays/IconPackFilledThemePickerOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackFilledThemePickerOverlay",
     theme: "IconPackFilledThemePicker",
diff --git a/packages/overlays/IconPackKaiAndroidOverlay/Android.bp b/packages/overlays/IconPackKaiAndroidOverlay/Android.bp
index 4161e25..ee588c1 100644
--- a/packages/overlays/IconPackKaiAndroidOverlay/Android.bp
+++ b/packages/overlays/IconPackKaiAndroidOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackKaiAndroidOverlay",
     theme: "IconPackKaiAndroid",
diff --git a/packages/overlays/IconPackKaiLauncherOverlay/Android.bp b/packages/overlays/IconPackKaiLauncherOverlay/Android.bp
index 4bf8f11..dcdad7a 100644
--- a/packages/overlays/IconPackKaiLauncherOverlay/Android.bp
+++ b/packages/overlays/IconPackKaiLauncherOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackKaiLauncherOverlay",
     theme: "IconPackKaiLauncher",
diff --git a/packages/overlays/IconPackKaiSettingsOverlay/Android.bp b/packages/overlays/IconPackKaiSettingsOverlay/Android.bp
index c43f9e5..974bb54 100644
--- a/packages/overlays/IconPackKaiSettingsOverlay/Android.bp
+++ b/packages/overlays/IconPackKaiSettingsOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackKaiSettingsOverlay",
     theme: "IconPackKaiSettings",
diff --git a/packages/overlays/IconPackKaiSystemUIOverlay/Android.bp b/packages/overlays/IconPackKaiSystemUIOverlay/Android.bp
index 22a8c28..b04ca61 100644
--- a/packages/overlays/IconPackKaiSystemUIOverlay/Android.bp
+++ b/packages/overlays/IconPackKaiSystemUIOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackKaiSystemUIOverlay",
     theme: "IconPackKaiSystemUI",
diff --git a/packages/overlays/IconPackKaiThemePickerOverlay/Android.bp b/packages/overlays/IconPackKaiThemePickerOverlay/Android.bp
index 85eb1c4..875cd1d 100644
--- a/packages/overlays/IconPackKaiThemePickerOverlay/Android.bp
+++ b/packages/overlays/IconPackKaiThemePickerOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackKaiThemePickerOverlay",
     theme: "IconPackKaiThemePicker",
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/Android.bp b/packages/overlays/IconPackRoundedAndroidOverlay/Android.bp
index 948f015..cb7b013 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/Android.bp
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackRoundedAndroidOverlay",
     theme: "IconPackRoundedAndroid",
diff --git a/packages/overlays/IconPackRoundedLauncherOverlay/Android.bp b/packages/overlays/IconPackRoundedLauncherOverlay/Android.bp
index 5fbe635..8ab6d95 100644
--- a/packages/overlays/IconPackRoundedLauncherOverlay/Android.bp
+++ b/packages/overlays/IconPackRoundedLauncherOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackRoundedLauncherOverlay",
     theme: "IconPackRoundedLauncher",
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/Android.bp b/packages/overlays/IconPackRoundedSettingsOverlay/Android.bp
index b1a0713..ee2f98a9 100644
--- a/packages/overlays/IconPackRoundedSettingsOverlay/Android.bp
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackRoundedSettingsOverlay",
     theme: "IconPackRoundedSettings",
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/Android.bp b/packages/overlays/IconPackRoundedSystemUIOverlay/Android.bp
index 6432998..ee0220a 100644
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/Android.bp
+++ b/packages/overlays/IconPackRoundedSystemUIOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackRoundedSystemUIOverlay",
     theme: "IconPackRoundedSystemUI",
diff --git a/packages/overlays/IconPackRoundedThemePickerOverlay/Android.bp b/packages/overlays/IconPackRoundedThemePickerOverlay/Android.bp
index 95e1d3a..d74765c 100644
--- a/packages/overlays/IconPackRoundedThemePickerOverlay/Android.bp
+++ b/packages/overlays/IconPackRoundedThemePickerOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackRoundedThemePickerOverlay",
     theme: "IconPackRoundedTheme",
diff --git a/packages/overlays/IconPackSamAndroidOverlay/Android.bp b/packages/overlays/IconPackSamAndroidOverlay/Android.bp
index e8c33b1..2e9dc34 100644
--- a/packages/overlays/IconPackSamAndroidOverlay/Android.bp
+++ b/packages/overlays/IconPackSamAndroidOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackSamAndroidOverlay",
     theme: "IconPackSamAndroid",
diff --git a/packages/overlays/IconPackSamLauncherOverlay/Android.bp b/packages/overlays/IconPackSamLauncherOverlay/Android.bp
index a469646..aa0cf00 100644
--- a/packages/overlays/IconPackSamLauncherOverlay/Android.bp
+++ b/packages/overlays/IconPackSamLauncherOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackSamLauncherOverlay",
     theme: "IconPackSamLauncher",
diff --git a/packages/overlays/IconPackSamSettingsOverlay/Android.bp b/packages/overlays/IconPackSamSettingsOverlay/Android.bp
index bc1fa45..a62037f 100644
--- a/packages/overlays/IconPackSamSettingsOverlay/Android.bp
+++ b/packages/overlays/IconPackSamSettingsOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackSamSettingsOverlay",
     theme: "IconPackSamSettings",
diff --git a/packages/overlays/IconPackSamSystemUIOverlay/Android.bp b/packages/overlays/IconPackSamSystemUIOverlay/Android.bp
index db77352..96ba7a0 100644
--- a/packages/overlays/IconPackSamSystemUIOverlay/Android.bp
+++ b/packages/overlays/IconPackSamSystemUIOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackSamSystemUIOverlay",
     theme: "IconPackSamSystemUI",
diff --git a/packages/overlays/IconPackSamThemePickerOverlay/Android.bp b/packages/overlays/IconPackSamThemePickerOverlay/Android.bp
index c216868..7376f03 100644
--- a/packages/overlays/IconPackSamThemePickerOverlay/Android.bp
+++ b/packages/overlays/IconPackSamThemePickerOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackSamThemePickerOverlay",
     theme: "IconPackSamThemePicker",
diff --git a/packages/overlays/IconPackVictorAndroidOverlay/Android.bp b/packages/overlays/IconPackVictorAndroidOverlay/Android.bp
index de62af1..ee73778 100644
--- a/packages/overlays/IconPackVictorAndroidOverlay/Android.bp
+++ b/packages/overlays/IconPackVictorAndroidOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackVictorAndroidOverlay",
     theme: "IconPackVictorAndroid",
diff --git a/packages/overlays/IconPackVictorLauncherOverlay/Android.bp b/packages/overlays/IconPackVictorLauncherOverlay/Android.bp
index fc4c360..a0cd45a 100644
--- a/packages/overlays/IconPackVictorLauncherOverlay/Android.bp
+++ b/packages/overlays/IconPackVictorLauncherOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackVictorLauncherOverlay",
     theme: "IconPackVictorLauncher",
diff --git a/packages/overlays/IconPackVictorSettingsOverlay/Android.bp b/packages/overlays/IconPackVictorSettingsOverlay/Android.bp
index 046bb3d..7807c6b 100644
--- a/packages/overlays/IconPackVictorSettingsOverlay/Android.bp
+++ b/packages/overlays/IconPackVictorSettingsOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackVictorSettingsOverlay",
     theme: "IconPackVictorSettings",
diff --git a/packages/overlays/IconPackVictorSystemUIOverlay/Android.bp b/packages/overlays/IconPackVictorSystemUIOverlay/Android.bp
index b8a9e77..2deb6cd 100644
--- a/packages/overlays/IconPackVictorSystemUIOverlay/Android.bp
+++ b/packages/overlays/IconPackVictorSystemUIOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackVictorSystemUIOverlay",
     theme: "IconPackVictorSystemUI",
diff --git a/packages/overlays/IconPackVictorThemePickerOverlay/Android.bp b/packages/overlays/IconPackVictorThemePickerOverlay/Android.bp
index 6f0144e..a18ebb3 100644
--- a/packages/overlays/IconPackVictorThemePickerOverlay/Android.bp
+++ b/packages/overlays/IconPackVictorThemePickerOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconPackVictorThemePickerOverlay",
     theme: "IconPackVictorThemePicker",
diff --git a/packages/overlays/IconShapeHeartOverlay/Android.bp b/packages/overlays/IconShapeHeartOverlay/Android.bp
index ec55712..1da8f4f 100644
--- a/packages/overlays/IconShapeHeartOverlay/Android.bp
+++ b/packages/overlays/IconShapeHeartOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconShapeHeartOverlay",
     theme: "IconShapeHeart",
diff --git a/packages/overlays/IconShapePebbleOverlay/Android.bp b/packages/overlays/IconShapePebbleOverlay/Android.bp
index 7dc4fde..fa2a5bb 100644
--- a/packages/overlays/IconShapePebbleOverlay/Android.bp
+++ b/packages/overlays/IconShapePebbleOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconShapePebbleOverlay",
     theme: "IconShapePebble",
diff --git a/packages/overlays/IconShapeRoundedRectOverlay/Android.bp b/packages/overlays/IconShapeRoundedRectOverlay/Android.bp
index b8b8531..5052d08f 100644
--- a/packages/overlays/IconShapeRoundedRectOverlay/Android.bp
+++ b/packages/overlays/IconShapeRoundedRectOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconShapeRoundedRectOverlay",
     theme: "IconShapeRoundedRect",
diff --git a/packages/overlays/IconShapeSquareOverlay/Android.bp b/packages/overlays/IconShapeSquareOverlay/Android.bp
index fdeffee..1176abd 100644
--- a/packages/overlays/IconShapeSquareOverlay/Android.bp
+++ b/packages/overlays/IconShapeSquareOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconShapeSquareOverlay",
     theme: "IconShapeSquare",
diff --git a/packages/overlays/IconShapeSquircleOverlay/Android.bp b/packages/overlays/IconShapeSquircleOverlay/Android.bp
index 468f0f7..8c219f3 100644
--- a/packages/overlays/IconShapeSquircleOverlay/Android.bp
+++ b/packages/overlays/IconShapeSquircleOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconShapeSquircleOverlay",
     theme: "IconShapeSquircle",
diff --git a/packages/overlays/IconShapeTaperedRectOverlay/Android.bp b/packages/overlays/IconShapeTaperedRectOverlay/Android.bp
index 1e48cd1..78855e8 100644
--- a/packages/overlays/IconShapeTaperedRectOverlay/Android.bp
+++ b/packages/overlays/IconShapeTaperedRectOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconShapeTaperedRectOverlay",
     theme: "IconShapeTaperedRect",
diff --git a/packages/overlays/IconShapeTeardropOverlay/Android.bp b/packages/overlays/IconShapeTeardropOverlay/Android.bp
index 017d58ec..dd36f4f 100644
--- a/packages/overlays/IconShapeTeardropOverlay/Android.bp
+++ b/packages/overlays/IconShapeTeardropOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconShapeTeardropOverlay",
     theme: "IconShapeTeardrop",
diff --git a/packages/overlays/IconShapeVesselOverlay/Android.bp b/packages/overlays/IconShapeVesselOverlay/Android.bp
index ba3b309..2e7f8bc 100644
--- a/packages/overlays/IconShapeVesselOverlay/Android.bp
+++ b/packages/overlays/IconShapeVesselOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "IconShapeVesselOverlay",
     theme: "IconShapeVessel",
diff --git a/packages/overlays/NavigationBarMode2ButtonOverlay/Android.bp b/packages/overlays/NavigationBarMode2ButtonOverlay/Android.bp
index e4fcce1..35f671ba 100644
--- a/packages/overlays/NavigationBarMode2ButtonOverlay/Android.bp
+++ b/packages/overlays/NavigationBarMode2ButtonOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "NavigationBarMode2ButtonOverlay",
     theme: "NavigationBarMode2Button",
diff --git a/packages/overlays/NavigationBarMode3ButtonOverlay/Android.bp b/packages/overlays/NavigationBarMode3ButtonOverlay/Android.bp
index 9b6c998..fe9cc81 100644
--- a/packages/overlays/NavigationBarMode3ButtonOverlay/Android.bp
+++ b/packages/overlays/NavigationBarMode3ButtonOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "NavigationBarMode3ButtonOverlay",
     theme: "NavigationBarMode3Button",
diff --git a/packages/overlays/NavigationBarModeGesturalOverlay/Android.bp b/packages/overlays/NavigationBarModeGesturalOverlay/Android.bp
index ba29045..791f420 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlay/Android.bp
+++ b/packages/overlays/NavigationBarModeGesturalOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "NavigationBarModeGesturalOverlay",
     theme: "NavigationBarModeGestural",
diff --git a/packages/overlays/NavigationBarModeGesturalOverlayExtraWideBack/Android.bp b/packages/overlays/NavigationBarModeGesturalOverlayExtraWideBack/Android.bp
index 0c688a9..28f9f33 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlayExtraWideBack/Android.bp
+++ b/packages/overlays/NavigationBarModeGesturalOverlayExtraWideBack/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "NavigationBarModeGesturalOverlayExtraWideBack",
     theme: "NavigationBarModeGesturalExtraWideBack",
diff --git a/packages/overlays/NavigationBarModeGesturalOverlayNarrowBack/Android.bp b/packages/overlays/NavigationBarModeGesturalOverlayNarrowBack/Android.bp
index 85d514f..f8a5603 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlayNarrowBack/Android.bp
+++ b/packages/overlays/NavigationBarModeGesturalOverlayNarrowBack/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "NavigationBarModeGesturalOverlayNarrowBack",
     theme: "NavigationBarModeGesturalNarrowBack",
diff --git a/packages/overlays/NavigationBarModeGesturalOverlayWideBack/Android.bp b/packages/overlays/NavigationBarModeGesturalOverlayWideBack/Android.bp
index 84be626..60ee6d5 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlayWideBack/Android.bp
+++ b/packages/overlays/NavigationBarModeGesturalOverlayWideBack/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "NavigationBarModeGesturalOverlayWideBack",
     theme: "NavigationBarModeGesturalWideBack",
diff --git a/packages/overlays/OneHandedModeGesturalOverlay/Android.bp b/packages/overlays/OneHandedModeGesturalOverlay/Android.bp
index 9c9d0ef..468069d 100644
--- a/packages/overlays/OneHandedModeGesturalOverlay/Android.bp
+++ b/packages/overlays/OneHandedModeGesturalOverlay/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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"],
+}
+
 runtime_resource_overlay {
     name: "OneHandedModeGesturalOverlay",
     theme: "OneHandedModeGestural",
diff --git a/packages/services/CameraExtensionsProxy/Android.bp b/packages/services/CameraExtensionsProxy/Android.bp
index e2e4af2..ea0703e 100644
--- a/packages/services/CameraExtensionsProxy/Android.bp
+++ b/packages/services/CameraExtensionsProxy/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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_app {
     name: "CameraExtensionsProxy",
     srcs: ["src/**/*.java"],
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 065e2bb..88e6b66 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -102,6 +102,10 @@
         FingerprintGestureDispatcher.FingerprintGestureClient {
     private static final boolean DEBUG = false;
     private static final String LOG_TAG = "AbstractAccessibilityServiceConnection";
+    private static final String TRACE_A11Y_SERVICE_CONNECTION =
+            LOG_TAG + ".IAccessibilityServiceConnection";
+    private static final String TRACE_A11Y_SERVICE_CLIENT =
+            LOG_TAG + ".IAccessibilityServiceClient";
     private static final int WAIT_WINDOWS_TIMEOUT_MILLIS = 5000;
 
     protected static final String TAKE_SCREENSHOT = "takeScreenshot";
@@ -127,6 +131,7 @@
     protected final Object mLock;
 
     protected final AccessibilitySecurityPolicy mSecurityPolicy;
+    protected final AccessibilityTrace mTrace;
 
     // The service that's bound to this instance. Whenever this value is non-null, this
     // object is registered as a death recipient
@@ -247,7 +252,7 @@
     public AbstractAccessibilityServiceConnection(Context context, ComponentName componentName,
             AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler,
             Object lock, AccessibilitySecurityPolicy securityPolicy, SystemSupport systemSupport,
-            WindowManagerInternal windowManagerInternal,
+            AccessibilityTrace trace, WindowManagerInternal windowManagerInternal,
             SystemActionPerformer systemActionPerfomer,
             AccessibilityWindowManager a11yWindowManager) {
         mContext = context;
@@ -259,6 +264,7 @@
         mSecurityPolicy = securityPolicy;
         mSystemActionPerformer = systemActionPerfomer;
         mSystemSupport = systemSupport;
+        mTrace = trace;
         mMainHandler = mainHandler;
         mInvocationHandler = new InvocationHandler(mainHandler.getLooper());
         mA11yWindowManager = a11yWindowManager;
@@ -291,6 +297,10 @@
             return false;
         }
         try {
+            if (mTrace.isA11yTracingEnabled()) {
+                mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onKeyEvent",
+                        keyEvent + ", " + sequenceNumber);
+            }
             mServiceInterface.onKeyEvent(keyEvent, sequenceNumber);
         } catch (RemoteException e) {
             return false;
@@ -354,11 +364,18 @@
 
     @Override
     public void setOnKeyEventResult(boolean handled, int sequence) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setOnKeyEventResult",
+                    "handled=" + handled + ";sequence=" + sequence);
+        }
         mSystemSupport.getKeyEventDispatcher().setOnKeyEventResult(this, handled, sequence);
     }
 
     @Override
     public AccessibilityServiceInfo getServiceInfo() {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getServiceInfo");
+        }
         synchronized (mLock) {
             return mAccessibilityServiceInfo;
         }
@@ -375,6 +392,9 @@
 
     @Override
     public void setServiceInfo(AccessibilityServiceInfo info) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setServiceInfo", "info=" + info);
+        }
         final long identity = Binder.clearCallingIdentity();
         try {
             synchronized (mLock) {
@@ -400,6 +420,9 @@
     @Nullable
     @Override
     public AccessibilityWindowInfo.WindowListSparseArray getWindows() {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getWindows");
+        }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
                 return null;
@@ -434,6 +457,9 @@
 
     @Override
     public AccessibilityWindowInfo getWindow(int windowId) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getWindow", "windowId=" + windowId);
+        }
         synchronized (mLock) {
             int displayId = Display.INVALID_DISPLAY;
             if (windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) {
@@ -469,6 +495,13 @@
             long accessibilityNodeId, String viewIdResName, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
             throws RemoteException {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".findAccessibilityNodeInfosByViewId",
+                    "accessibilityWindowId=" + accessibilityWindowId + ";accessibilityNodeId="
+                    + accessibilityNodeId + ";viewIdResName=" + viewIdResName + ";interactionId="
+                    + interactionId + ";callback=" + callback + ";interrogatingTid="
+                    + interrogatingTid);
+        }
         final int resolvedWindowId;
         RemoteAccessibilityConnection connection;
         Region partialInteractiveRegion = Region.obtain();
@@ -530,6 +563,12 @@
             long accessibilityNodeId, String text, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
             throws RemoteException {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".findAccessibilityNodeInfosByText",
+                    "accessibilityWindowId=" + accessibilityWindowId + ";accessibilityNodeId="
+                    + accessibilityNodeId + ";text=" + text + ";interactionId=" + interactionId
+                    + ";callback=" + callback + ";interrogatingTid=" + interrogatingTid);
+        }
         final int resolvedWindowId;
         RemoteAccessibilityConnection connection;
         Region partialInteractiveRegion = Region.obtain();
@@ -591,6 +630,14 @@
             int accessibilityWindowId, long accessibilityNodeId, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, int flags,
             long interrogatingTid, Bundle arguments) throws RemoteException {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(
+                    TRACE_A11Y_SERVICE_CONNECTION + ".findAccessibilityNodeInfoByAccessibilityId",
+                    "accessibilityWindowId=" + accessibilityWindowId + ";accessibilityNodeId="
+                            + accessibilityNodeId + ";interactionId=" + interactionId + ";callback="
+                            + callback + ";flags=" + flags + ";interrogatingTid=" + interrogatingTid
+                            + ";arguments=" + arguments);
+        }
         final int resolvedWindowId;
         RemoteAccessibilityConnection connection;
         Region partialInteractiveRegion = Region.obtain();
@@ -652,6 +699,13 @@
             int focusType, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
             throws RemoteException {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".findFocus",
+                    "accessibilityWindowId=" + accessibilityWindowId + ";accessibilityNodeId="
+                            + accessibilityNodeId + ";focusType=" + focusType + ";interactionId="
+                            + interactionId + ";callback=" + callback + ";interrogatingTid="
+                            + interrogatingTid);
+        }
         final int resolvedWindowId;
         RemoteAccessibilityConnection connection;
         Region partialInteractiveRegion = Region.obtain();
@@ -713,6 +767,13 @@
             int direction, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
             throws RemoteException {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".focusSearch",
+                    "accessibilityWindowId=" + accessibilityWindowId + ";accessibilityNodeId="
+                            + accessibilityNodeId + ";direction=" + direction + ";interactionId="
+                            + interactionId + ";callback=" + callback + ";interrogatingTid="
+                            + interrogatingTid);
+        }
         final int resolvedWindowId;
         RemoteAccessibilityConnection connection;
         Region partialInteractiveRegion = Region.obtain();
@@ -770,10 +831,18 @@
 
     @Override
     public void sendGesture(int sequence, ParceledListSlice gestureSteps) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".sendGesture",
+                    "sequence=" + sequence + ";gestureSteps=" + gestureSteps);
+        }
     }
 
     @Override
     public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".dispatchGesture", "sequence="
+                    + sequence + ";gestureSteps=" + gestureSteps + ";displayId=" + displayId);
+        }
     }
 
     @Override
@@ -781,6 +850,13 @@
             long accessibilityNodeId, int action, Bundle arguments, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
             throws RemoteException {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".performAccessibilityAction",
+                    "accessibilityWindowId=" + accessibilityWindowId + ";accessibilityNodeId="
+                            + accessibilityNodeId + ";action=" + action + ";arguments=" + arguments
+                            + ";interactionId=" + interactionId + ";callback=" + callback
+                            + ";interrogatingTid=" + interrogatingTid);
+        }
         final int resolvedWindowId;
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
@@ -802,6 +878,10 @@
 
     @Override
     public boolean performGlobalAction(int action) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".performGlobalAction",
+                    "action=" + action);
+        }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
                 return false;
@@ -812,6 +892,9 @@
 
     @Override
     public @NonNull List<AccessibilityNodeInfo.AccessibilityAction> getSystemActions() {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getSystemActions");
+        }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
                 return Collections.emptyList();
@@ -822,6 +905,10 @@
 
     @Override
     public boolean isFingerprintGestureDetectionAvailable() {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(
+                    TRACE_A11Y_SERVICE_CONNECTION + ".isFingerprintGestureDetectionAvailable");
+        }
         if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
             return false;
         }
@@ -835,6 +922,10 @@
 
     @Override
     public float getMagnificationScale(int displayId) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getMagnificationScale",
+                    "displayId=" + displayId);
+        }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
                 return 1.0f;
@@ -850,6 +941,10 @@
 
     @Override
     public Region getMagnificationRegion(int displayId) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getMagnificationRegion",
+                    "displayId=" + displayId);
+        }
         synchronized (mLock) {
             final Region region = Region.obtain();
             if (!hasRightsToCurrentUserLocked()) {
@@ -874,6 +969,10 @@
 
     @Override
     public float getMagnificationCenterX(int displayId) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getMagnificationCenterX",
+                    "displayId=" + displayId);
+        }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
                 return 0.0f;
@@ -896,6 +995,10 @@
 
     @Override
     public float getMagnificationCenterY(int displayId) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getMagnificationCenterY",
+                    "displayId=" + displayId);
+        }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
                 return 0.0f;
@@ -928,6 +1031,10 @@
 
     @Override
     public boolean resetMagnification(int displayId, boolean animate) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".resetMagnification",
+                    "displayId=" + displayId + ";animate=" + animate);
+        }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
                 return false;
@@ -950,6 +1057,11 @@
     @Override
     public boolean setMagnificationScaleAndCenter(int displayId, float scale, float centerX,
             float centerY, boolean animate) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setMagnificationScaleAndCenter",
+                    "displayId=" + displayId + ";scale=" + scale + ";centerX=" + centerX
+                            + ";centerY=" + centerY + ";animate=" + animate);
+        }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
                 return false;
@@ -974,6 +1086,10 @@
 
     @Override
     public void setMagnificationCallbackEnabled(int displayId, boolean enabled) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setMagnificationCallbackEnabled",
+                    "displayId=" + displayId + ";enabled=" + enabled);
+        }
         mInvocationHandler.setMagnificationCallbackEnabled(displayId, enabled);
     }
 
@@ -983,11 +1099,19 @@
 
     @Override
     public void setSoftKeyboardCallbackEnabled(boolean enabled) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setSoftKeyboardCallbackEnabled",
+                    "enabled=" + enabled);
+        }
         mInvocationHandler.setSoftKeyboardCallbackEnabled(enabled);
     }
 
     @Override
     public void takeScreenshot(int displayId, RemoteCallback callback) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".takeScreenshot",
+                    "displayId=" + displayId + ";callback=" + callback);
+        }
         final long currentTimestamp = SystemClock.uptimeMillis();
         if (mRequestTakeScreenshotTimestampMs != 0
                 && (currentTimestamp - mRequestTakeScreenshotTimestampMs)
@@ -1157,6 +1281,10 @@
      */
     @Override
     public IBinder getOverlayWindowToken(int displayId) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getOverlayWindowToken",
+                    "displayId=" + displayId);
+        }
         synchronized (mLock) {
             return mOverlayWindowTokens.get(displayId);
         }
@@ -1170,6 +1298,10 @@
      */
     @Override
     public int getWindowIdForLeashToken(@NonNull IBinder token) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getWindowIdForLeashToken",
+                    "token=" + token);
+        }
         synchronized (mLock) {
             return mA11yWindowManager.getWindowIdLocked(token);
         }
@@ -1181,6 +1313,9 @@
             // Clear the proxy in the other process so this
             // IAccessibilityServiceConnection can be garbage collected.
             if (mServiceInterface != null) {
+                if (mTrace.isA11yTracingEnabled()) {
+                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".init", "null, " + mId + ", null");
+                }
                 mServiceInterface.init(null, mId, null);
             }
         } catch (RemoteException re) {
@@ -1329,6 +1464,10 @@
         }
 
         try {
+            if (mTrace.isA11yTracingEnabled()) {
+                mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onAccessibilityEvent",
+                        event + ";" + serviceWantsEvent);
+            }
             listener.onAccessibilityEvent(event, serviceWantsEvent);
             if (DEBUG) {
                 Slog.i(LOG_TAG, "Event " + event + " sent to " + listener);
@@ -1382,6 +1521,10 @@
         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
         if (listener != null) {
             try {
+                if (mTrace.isA11yTracingEnabled()) {
+                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onMagnificationChanged", displayId
+                            + ", " + region + ", " + scale + ", " + centerX + ", " + centerY);
+                }
                 listener.onMagnificationChanged(displayId, region, scale, centerX, centerY);
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG, "Error sending magnification changes to " + mService, re);
@@ -1397,6 +1540,10 @@
         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
         if (listener != null) {
             try {
+                if (mTrace.isA11yTracingEnabled()) {
+                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onSoftKeyboardShowModeChanged",
+                            String.valueOf(showState));
+                }
                 listener.onSoftKeyboardShowModeChanged(showState);
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG, "Error sending soft keyboard show mode changes to " + mService,
@@ -1409,6 +1556,10 @@
         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
         if (listener != null) {
             try {
+                if (mTrace.isA11yTracingEnabled()) {
+                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onAccessibilityButtonClicked",
+                            String.valueOf(displayId));
+                }
                 listener.onAccessibilityButtonClicked(displayId);
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG, "Error sending accessibility button click to " + mService, re);
@@ -1427,6 +1578,11 @@
         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
         if (listener != null) {
             try {
+                if (mTrace.isA11yTracingEnabled()) {
+                    mTrace.logTrace(
+                            TRACE_A11Y_SERVICE_CLIENT + ".onAccessibilityButtonAvailabilityChanged",
+                            String.valueOf(available));
+                }
                 listener.onAccessibilityButtonAvailabilityChanged(available);
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG,
@@ -1440,6 +1596,10 @@
         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
         if (listener != null) {
             try {
+                if (mTrace.isA11yTracingEnabled()) {
+                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onGesture",
+                            gestureInfo.toString());
+                }
                 listener.onGesture(gestureInfo);
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG, "Error during sending gesture " + gestureInfo
@@ -1452,6 +1612,9 @@
         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
         if (listener != null) {
             try {
+                if (mTrace.isA11yTracingEnabled()) {
+                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onSystemActionsChanged");
+                }
                 listener.onSystemActionsChanged();
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG, "Error sending system actions change to " + mService,
@@ -1464,6 +1627,9 @@
         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
         if (listener != null) {
             try {
+                if (mTrace.isA11yTracingEnabled()) {
+                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".clearAccessibilityCache");
+                }
                 listener.clearAccessibilityCache();
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG, "Error during requesting accessibility info cache"
@@ -1790,14 +1956,27 @@
 
     @Override
     public void setGestureDetectionPassthroughRegion(int displayId, Region region) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setGestureDetectionPassthroughRegion",
+                    "displayId=" + displayId + ";region=" + region);
+        }
         mSystemSupport.setGestureDetectionPassthroughRegion(displayId, region);
     }
 
     @Override
     public void setTouchExplorationPassthroughRegion(int displayId, Region region) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setTouchExplorationPassthroughRegion",
+                    "displayId=" + displayId + ";region=" + region);
+        }
         mSystemSupport.setTouchExplorationPassthroughRegion(displayId, region);
     }
 
     @Override
-    public void setFocusAppearance(int strokeWidth, int color) { }
+    public void setFocusAppearance(int strokeWidth, int color) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setFocusAppearance",
+                    "strokeWidth=" + strokeWidth + ";color=" + color);
+        }
+    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index c63c2e1..b3be044 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -149,6 +149,7 @@
  */
 public class AccessibilityManagerService extends IAccessibilityManager.Stub
         implements AbstractAccessibilityServiceConnection.SystemSupport,
+        AccessibilityTrace,
         AccessibilityUserState.ServiceInfoChangeListener,
         AccessibilityWindowManager.AccessibilityEventSender,
         AccessibilitySecurityPolicy.AccessibilityUserManager,
@@ -243,6 +244,7 @@
     final SparseArray<AccessibilityUserState> mUserStates = new SparseArray<>();
 
     private final UiAutomationManager mUiAutomationManager = new UiAutomationManager(mLock);
+    private final WindowManagerInternal.AccessibilityControllerInternal mA11yController;
 
     private int mCurrentUserId = UserHandle.USER_SYSTEM;
 
@@ -288,6 +290,7 @@
         mContext = context;
         mPowerManager =  (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
+        mA11yController = mWindowManagerService.getAccessibilityController();
         mMainHandler = new MainHandler(mContext.getMainLooper());
         mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class);
         mPackageManager = packageManager;
@@ -308,6 +311,7 @@
         mContext = context;
         mPowerManager =  (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
+        mA11yController = mWindowManagerService.getAccessibilityController();
         mMainHandler = new MainHandler(mContext.getMainLooper());
         mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class);
         mPackageManager = mContext.getPackageManager();
@@ -328,16 +332,25 @@
 
     @Override
     public int getCurrentUserIdLocked() {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".getCurrentUserIdLocked");
+        }
         return mCurrentUserId;
     }
 
     @Override
     public boolean isAccessibilityButtonShown() {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".isAccessibilityButtonShown");
+        }
         return mIsAccessibilityButtonShown;
     }
 
     @Override
     public void onServiceInfoChangedLocked(AccessibilityUserState userState) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".onServiceInfoChangedLocked", "userState=" + userState);
+        }
         scheduleNotifyClientsOfServicesStateChangeLocked(userState);
     }
 
@@ -395,6 +408,10 @@
         PackageMonitor monitor = new PackageMonitor() {
             @Override
             public void onSomePackagesChanged() {
+                if (isA11yTracingEnabled()) {
+                    logTrace(LOG_TAG + ".PM.onSomePackagesChanged");
+                }
+
                 synchronized (mLock) {
                     // Only the profile parent can install accessibility services.
                     // Therefore we ignore packages from linked profiles.
@@ -419,6 +436,10 @@
                 // mBindingServices in binderDied() during updating. Remove services from  this
                 // package from mBindingServices, and then update the user state to re-bind new
                 // versions of them.
+                if (isA11yTracingEnabled()) {
+                    logTrace(LOG_TAG + ".PM.onPackageUpdateFinished",
+                            "packageName=" + packageName + ";uid=" + uid);
+                }
                 synchronized (mLock) {
                     final int userId = getChangingUserId();
                     if (userId != mCurrentUserId) {
@@ -448,6 +469,11 @@
 
             @Override
             public void onPackageRemoved(String packageName, int uid) {
+                if (isA11yTracingEnabled()) {
+                    logTrace(LOG_TAG + ".PM.onPackageRemoved",
+                            "packageName=" + packageName + ";uid=" + uid);
+                }
+
                 synchronized (mLock) {
                     final int userId = getChangingUserId();
                     // Only the profile parent can install accessibility services.
@@ -487,6 +513,10 @@
             @Override
             public boolean onHandleForceStop(Intent intent, String[] packages,
                     int uid, boolean doit) {
+                if (isA11yTracingEnabled()) {
+                    logTrace(LOG_TAG + ".PM.onHandleForceStop", "intent=" + intent + ";packages="
+                            + packages + ";uid=" + uid + ";doit=" + doit);
+                }
                 synchronized (mLock) {
                     final int userId = getChangingUserId();
                     // Only the profile parent can install accessibility services.
@@ -533,6 +563,10 @@
         mContext.registerReceiverAsUser(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
+                if (isA11yTracingEnabled()) {
+                    logTrace(LOG_TAG + ".BR.onReceive", "context=" + context + ";intent=" + intent);
+                }
+
                 String action = intent.getAction();
                 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                     switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
@@ -616,6 +650,10 @@
 
     @Override
     public long addClient(IAccessibilityManagerClient callback, int userId) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".addClient", "callback=" + callback + ";userId=" + userId);
+        }
+
         synchronized (mLock) {
             // We treat calls from a profile as if made by its parent as profiles
             // share the accessibility state of the parent. The call below
@@ -654,6 +692,9 @@
 
     @Override
     public void sendAccessibilityEvent(AccessibilityEvent event, int userId) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".sendAccessibilityEvent", "event=" + event + ";userId=" + userId);
+        }
         boolean dispatchEvent = false;
 
         synchronized (mLock) {
@@ -746,6 +787,10 @@
      */
     @Override
     public void registerSystemAction(RemoteAction action, int actionId) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".registerSystemAction", "action=" + action + ";actionId="
+                    + actionId);
+        }
         mSecurityPolicy.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY);
         getSystemActionPerformer().registerSystemAction(actionId, action);
     }
@@ -757,6 +802,9 @@
      */
     @Override
     public void unregisterSystemAction(int actionId) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".unregisterSystemAction", "actionId=" + actionId);
+        }
         mSecurityPolicy.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY);
         getSystemActionPerformer().unregisterSystemAction(actionId);
     }
@@ -771,6 +819,10 @@
 
     @Override
     public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".getInstalledAccessibilityServiceList", "userId=" + userId);
+        }
+
         synchronized (mLock) {
             // We treat calls from a profile as if made by its parent as profiles
             // share the accessibility state of the parent. The call below
@@ -788,6 +840,11 @@
     @Override
     public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType,
             int userId) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".getEnabledAccessibilityServiceList",
+                    "feedbackType=" + feedbackType + ";userId=" + userId);
+        }
+
         synchronized (mLock) {
             // We treat calls from a profile as if made by its parent as profiles
             // share the accessibility state of the parent. The call below
@@ -816,6 +873,10 @@
 
     @Override
     public void interrupt(int userId) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".interrupt", "userId=" + userId);
+        }
+
         List<IAccessibilityServiceClient> interfacesToInterrupt;
         synchronized (mLock) {
             // We treat calls from a profile as if made by its parent as profiles
@@ -842,6 +903,9 @@
         }
         for (int i = 0, count = interfacesToInterrupt.size(); i < count; i++) {
             try {
+                if (isA11yTracingEnabled()) {
+                    logTrace(LOG_TAG + ".IAccessibilityServiceClient.onInterrupt");
+                }
                 interfacesToInterrupt.get(i).onInterrupt();
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG, "Error sending interrupt request to "
@@ -854,18 +918,31 @@
     public int addAccessibilityInteractionConnection(IWindow windowToken, IBinder leashToken,
             IAccessibilityInteractionConnection connection, String packageName,
             int userId) throws RemoteException {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".addAccessibilityInteractionConnection",
+                    "windowToken=" + windowToken + "leashToken=" + leashToken + ";connection="
+                            + connection + "; packageName=" + packageName + ";userId=" + userId);
+        }
+
         return mA11yWindowManager.addAccessibilityInteractionConnection(
                 windowToken, leashToken, connection, packageName, userId);
     }
 
     @Override
     public void removeAccessibilityInteractionConnection(IWindow window) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".removeAccessibilityInteractionConnection", "window=" + window);
+        }
         mA11yWindowManager.removeAccessibilityInteractionConnection(window);
     }
 
     @Override
     public void setPictureInPictureActionReplacingConnection(
             IAccessibilityInteractionConnection connection) throws RemoteException {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".setPictureInPictureActionReplacingConnection",
+                    "connection=" + connection);
+        }
         mSecurityPolicy.enforceCallingPermission(Manifest.permission.MODIFY_ACCESSIBILITY_DATA,
                 SET_PIP_ACTION_REPLACEMENT);
         mA11yWindowManager.setPictureInPictureActionReplacingConnection(connection);
@@ -876,13 +953,19 @@
             IAccessibilityServiceClient serviceClient,
             AccessibilityServiceInfo accessibilityServiceInfo,
             int flags) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".registerUiTestAutomationService", "owner=" + owner
+                    + ";serviceClient=" + serviceClient + ";accessibilityServiceInfo="
+                    + accessibilityServiceInfo + ";flags=" + flags);
+        }
+
         mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT,
                 FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE);
 
         synchronized (mLock) {
             mUiAutomationManager.registerUiTestAutomationServiceLocked(owner, serviceClient,
                     mContext, accessibilityServiceInfo, sIdCounter++, mMainHandler,
-                    mSecurityPolicy, this, mWindowManagerService, getSystemActionPerformer(),
+                    mSecurityPolicy, this, this, mWindowManagerService, getSystemActionPerformer(),
                     mA11yWindowManager, flags);
             onUserStateChangedLocked(getCurrentUserStateLocked());
         }
@@ -890,6 +973,10 @@
 
     @Override
     public void unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".unregisterUiTestAutomationService",
+                    "serviceClient=" + serviceClient);
+        }
         synchronized (mLock) {
             mUiAutomationManager.unregisterUiTestAutomationServiceLocked(serviceClient);
         }
@@ -898,6 +985,11 @@
     @Override
     public void temporaryEnableAccessibilityStateUntilKeyguardRemoved(
             ComponentName service, boolean touchExplorationEnabled) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".temporaryEnableAccessibilityStateUntilKeyguardRemoved",
+                    "service=" + service + ";touchExplorationEnabled=" + touchExplorationEnabled);
+        }
+
         mSecurityPolicy.enforceCallingPermission(
                 Manifest.permission.TEMPORARY_ENABLE_ACCESSIBILITY,
                 TEMPORARY_ENABLE_ACCESSIBILITY_UNTIL_KEYGUARD_REMOVED);
@@ -926,6 +1018,10 @@
 
     @Override
     public IBinder getWindowToken(int windowId, int userId) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".getWindowToken", "windowId=" + windowId + ";userId=" + userId);
+        }
+
         mSecurityPolicy.enforceCallingPermission(
                 Manifest.permission.RETRIEVE_WINDOW_TOKEN,
                 GET_WINDOW_TOKEN);
@@ -965,6 +1061,11 @@
      */
     @Override
     public void notifyAccessibilityButtonClicked(int displayId, String targetName) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".notifyAccessibilityButtonClicked",
+                    "displayId=" + displayId + ";targetName=" + targetName);
+        }
+
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Caller does not hold permission "
@@ -990,6 +1091,10 @@
      */
     @Override
     public void notifyAccessibilityButtonVisibilityChanged(boolean shown) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".notifyAccessibilityButtonVisibilityChanged", "shown=" + shown);
+        }
+
         mSecurityPolicy.enforceCallingOrSelfPermission(
                 android.Manifest.permission.STATUS_BAR_SERVICE);
         synchronized (mLock) {
@@ -1018,6 +1123,10 @@
      */
     @Override
     public void onSystemActionsChanged() {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".onSystemActionsChanged");
+        }
+
         synchronized (mLock) {
             AccessibilityUserState state = getCurrentUserStateLocked();
             notifySystemActionsChangedLocked(state);
@@ -1080,6 +1189,10 @@
 
     @Override
     public @Nullable MotionEventInjector getMotionEventInjectorForDisplayLocked(int displayId) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".getMotionEventInjectorForDisplayLocked", "displayId=" + displayId);
+        }
+
         final long endMillis = SystemClock.uptimeMillis() + WAIT_MOTION_INJECTOR_TIMEOUT_MILLIS;
         MotionEventInjector motionEventInjector = null;
         while ((mMotionEventInjectors == null) && (SystemClock.uptimeMillis() < endMillis)) {
@@ -1646,6 +1759,11 @@
     @Override
     public void persistComponentNamesToSettingLocked(String settingName,
             Set<ComponentName> componentNames, int userId) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".persistComponentNamesToSettingLocked", "settingName=" + settingName
+                    + ";componentNames=" + componentNames + ";userId=" + userId);
+        }
+
         persistColonDelimitedSetToSettingLocked(settingName, userId, componentNames,
                 componentName -> componentName.flattenToShortString());
     }
@@ -1730,7 +1848,7 @@
                 if (service == null) {
                     service = new AccessibilityServiceConnection(userState, mContext, componentName,
                             installedService, sIdCounter++, mMainHandler, mLock, mSecurityPolicy,
-                            this, mWindowManagerService, getSystemActionPerformer(),
+                            this, this, mWindowManagerService, getSystemActionPerformer(),
                             mA11yWindowManager, mActivityTaskManagerService);
                 } else if (userState.mBoundServices.contains(service)) {
                     continue;
@@ -2607,6 +2725,10 @@
     @GuardedBy("mLock")
     @Override
     public MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".getCompatibleMagnificationSpecLocked", "windowId=" + windowId);
+        }
+
         IBinder windowToken = mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(
                 mCurrentUserId, windowId);
         if (windowToken != null) {
@@ -2618,6 +2740,10 @@
 
     @Override
     public KeyEventDispatcher getKeyEventDispatcher() {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".getKeyEventDispatcher");
+        }
+
         if (mKeyEventDispatcher == null) {
             mKeyEventDispatcher = new KeyEventDispatcher(
                     mMainHandler, MainHandler.MSG_SEND_KEY_EVENT_TO_INPUT_FILTER, mLock,
@@ -2630,6 +2756,12 @@
     @SuppressWarnings("AndroidFrameworkPendingIntentMutability")
     public PendingIntent getPendingIntentActivity(Context context, int requestCode, Intent intent,
             int flags) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".getPendingIntentActivity", "context=" + context + ";requestCode="
+                    + requestCode + ";intent=" + intent + ";flags=" + flags);
+        }
+
+
         return PendingIntent.getActivity(context, requestCode, intent, flags);
     }
 
@@ -2644,6 +2776,10 @@
      */
     @Override
     public void performAccessibilityShortcut(String targetName) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".performAccessibilityShortcut", "targetName=" + targetName);
+        }
+
         if ((UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID)
                 && (mContext.checkCallingPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
                 != PackageManager.PERMISSION_GRANTED)) {
@@ -2828,6 +2964,10 @@
 
     @Override
     public List<String> getAccessibilityShortcutTargets(@ShortcutType int shortcutType) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".getAccessibilityShortcutTargets", "shortcutType=" + shortcutType);
+        }
+
         if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException(
@@ -2897,6 +3037,10 @@
 
     @Override
     public void sendAccessibilityEventForCurrentUserLocked(AccessibilityEvent event) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".sendAccessibilityEventForCurrentUserLocked", "event=" + event);
+        }
+
         sendAccessibilityEventLocked(event, mCurrentUserId);
     }
 
@@ -2918,6 +3062,10 @@
      */
     @Override
     public boolean sendFingerprintGesture(int gestureKeyCode) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".sendFingerprintGesture", "gestureKeyCode=" + gestureKeyCode);
+        }
+
         synchronized(mLock) {
             if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
                 throw new SecurityException("Only SYSTEM can call sendFingerprintGesture");
@@ -2939,6 +3087,10 @@
      */
     @Override
     public int getAccessibilityWindowId(@Nullable IBinder windowToken) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".getAccessibilityWindowId", "windowToken=" + windowToken);
+        }
+
         synchronized (mLock) {
             if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
                 throw new SecurityException("Only SYSTEM can call getAccessibilityWindowId");
@@ -2956,6 +3108,10 @@
      */
     @Override
     public long getRecommendedTimeoutMillis() {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".getRecommendedTimeoutMillis");
+        }
+
         synchronized(mLock) {
             final AccessibilityUserState userState = getCurrentUserStateLocked();
             return getRecommendedTimeoutMillisLocked(userState);
@@ -2970,6 +3126,10 @@
     @Override
     public void setWindowMagnificationConnection(
             IWindowMagnificationConnection connection) throws RemoteException {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".setWindowMagnificationConnection", "connection=" + connection);
+        }
+
         mSecurityPolicy.enforceCallingOrSelfPermission(
                 android.Manifest.permission.STATUS_BAR_SERVICE);
 
@@ -3000,6 +3160,11 @@
 
     @Override
     public void associateEmbeddedHierarchy(@NonNull IBinder host, @NonNull IBinder embedded) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".associateEmbeddedHierarchy",
+                    "host=" + host + ";embedded=" + embedded);
+        }
+
         synchronized (mLock) {
             mA11yWindowManager.associateEmbeddedHierarchyLocked(host, embedded);
         }
@@ -3007,6 +3172,10 @@
 
     @Override
     public void disassociateEmbeddedHierarchy(@NonNull IBinder token) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".disassociateEmbeddedHierarchy", "token=" + token);
+        }
+
         synchronized (mLock) {
             mA11yWindowManager.disassociateEmbeddedHierarchyLocked(token);
         }
@@ -3084,6 +3253,9 @@
 
     @Override
     public FullScreenMagnificationController getFullScreenMagnificationController() {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".getFullScreenMagnificationController");
+        }
         synchronized (mLock) {
             return mMagnificationController.getFullScreenMagnificationController();
         }
@@ -3091,6 +3263,10 @@
 
     @Override
     public void onClientChangeLocked(boolean serviceInfoChanged) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".onClientChangeLocked", "serviceInfoChanged=" + serviceInfoChanged);
+        }
+
         AccessibilityUserState userState = getUserStateLocked(mCurrentUserId);
         onUserStateChangedLocked(userState);
         if (serviceInfoChanged) {
@@ -3126,8 +3302,9 @@
             AccessibilityServiceConnection service = new AccessibilityServiceConnection(
                     userState, mContext,
                     COMPONENT_NAME, info, sIdCounter++, mMainHandler, mLock, mSecurityPolicy,
-                    AccessibilityManagerService.this, mWindowManagerService,
-                    getSystemActionPerformer(), mA11yWindowManager, mActivityTaskManagerService) {
+                    AccessibilityManagerService.this, AccessibilityManagerService.this,
+                    mWindowManagerService, getSystemActionPerformer(), mA11yWindowManager,
+                    mActivityTaskManagerService) {
                 @Override
                 public boolean supportsFlagForNotImportantViews(AccessibilityServiceInfo info) {
                     return true;
@@ -3614,6 +3791,11 @@
 
     @Override
     public void setGestureDetectionPassthroughRegion(int displayId, Region region) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".setGestureDetectionPassthroughRegion",
+                    "displayId=" + displayId + ";region=" + region);
+        }
+
         mMainHandler.sendMessage(
                 obtainMessage(
                         AccessibilityManagerService::setGestureDetectionPassthroughRegionInternal,
@@ -3624,6 +3806,11 @@
 
     @Override
     public void setTouchExplorationPassthroughRegion(int displayId, Region region) {
+        if (isA11yTracingEnabled()) {
+            logTrace(LOG_TAG + ".setTouchExplorationPassthroughRegion",
+                    "displayId=" + displayId + ";region=" + region);
+        }
+
         mMainHandler.sendMessage(
                 obtainMessage(
                         AccessibilityManagerService::setTouchExplorationPassthroughRegionInternal,
@@ -3661,4 +3848,20 @@
         });
 
     }
+
+    @Override
+    public boolean isA11yTracingEnabled() {
+        return mA11yController.isAccessibilityTracingEnabled();
+    }
+
+    @Override
+    public void logTrace(String where) {
+        logTrace(where, "");
+    }
+
+    @Override
+    public void logTrace(String where, String callingParams) {
+        mA11yController.logTrace(where, callingParams, "".getBytes(),
+                Binder.getCallingUid(), Thread.currentThread().getStackTrace());
+    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 6756268..7d75b73 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -53,6 +53,10 @@
  */
 class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnection {
     private static final String LOG_TAG = "AccessibilityServiceConnection";
+    private static final String TRACE_A11Y_SERVICE_CONNECTION =
+            LOG_TAG + ".IAccessibilityServiceConnection";
+    private static final String TRACE_A11Y_SERVICE_CLIENT =
+            LOG_TAG + ".IAccessibilityServiceClient";
     /*
      Holding a weak reference so there isn't a loop of references. AccessibilityUserState keeps
      lists of bound and binding services. These are freed on user changes, but just in case it
@@ -70,11 +74,12 @@
             ComponentName componentName,
             AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler,
             Object lock, AccessibilitySecurityPolicy securityPolicy, SystemSupport systemSupport,
-            WindowManagerInternal windowManagerInternal,
+            AccessibilityTrace trace, WindowManagerInternal windowManagerInternal,
             SystemActionPerformer systemActionPerfomer, AccessibilityWindowManager awm,
             ActivityTaskManagerInternal activityTaskManagerService) {
         super(context, componentName, accessibilityServiceInfo, id, mainHandler, lock,
-                securityPolicy, systemSupport, windowManagerInternal, systemActionPerfomer, awm);
+                securityPolicy, systemSupport, trace, windowManagerInternal, systemActionPerfomer,
+                awm);
         mUserStateWeakReference = new WeakReference<AccessibilityUserState>(userState);
         mIntent = new Intent().setComponent(mComponentName);
         mMainHandler = mainHandler;
@@ -132,6 +137,9 @@
 
     @Override
     public void disableSelf() {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".disableSelf");
+        }
         synchronized (mLock) {
             AccessibilityUserState userState = mUserStateWeakReference.get();
             if (userState == null) return;
@@ -210,6 +218,10 @@
             return;
         }
         try {
+            if (mTrace.isA11yTracingEnabled()) {
+                mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".init", this + ", " + mId + ", "
+                        + mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY));
+            }
             serviceInterface.init(this, mId, mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY));
         } catch (RemoteException re) {
             Slog.w(LOG_TAG, "Error while setting connection for service: "
@@ -252,6 +264,10 @@
 
     @Override
     public boolean setSoftKeyboardShowMode(int showMode) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setSoftKeyboardShowMode",
+                    "showMode=" + showMode);
+        }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
                 return false;
@@ -264,12 +280,19 @@
 
     @Override
     public int getSoftKeyboardShowMode() {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getSoftKeyboardShowMode");
+        }
         final AccessibilityUserState userState = mUserStateWeakReference.get();
         return (userState != null) ? userState.getSoftKeyboardShowModeLocked() : 0;
     }
 
     @Override
     public boolean switchToInputMethod(String imeId) {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".switchToInputMethod",
+                    "imeId=" + imeId);
+        }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
                 return false;
@@ -288,6 +311,9 @@
 
     @Override
     public boolean isAccessibilityButtonAvailable() {
+        if (mTrace.isA11yTracingEnabled()) {
+            mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".isAccessibilityButtonAvailable");
+        }
         synchronized (mLock) {
             if (!hasRightsToCurrentUserLocked()) {
                 return false;
@@ -347,6 +373,10 @@
         }
         if (serviceInterface != null) {
             try {
+                if (mTrace.isA11yTracingEnabled()) {
+                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT
+                            + ".onFingerprintCapturingGesturesChanged", String.valueOf(active));
+                }
                 mServiceInterface.onFingerprintCapturingGesturesChanged(active);
             } catch (RemoteException e) {
             }
@@ -364,6 +394,10 @@
         }
         if (serviceInterface != null) {
             try {
+                if (mTrace.isA11yTracingEnabled()) {
+                    mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onFingerprintGesture",
+                            String.valueOf(gesture));
+                }
                 mServiceInterface.onFingerprintGesture(gesture);
             } catch (RemoteException e) {
             }
@@ -382,6 +416,10 @@
                             gestureSteps.getList(), mServiceInterface, sequence, displayId);
                 } else {
                     try {
+                        if (mTrace.isA11yTracingEnabled()) {
+                            mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onPerformGestureResult",
+                                    sequence + ", false");
+                        }
                         mServiceInterface.onPerformGestureResult(sequence, false);
                     } catch (RemoteException re) {
                         Slog.e(LOG_TAG, "Error sending motion event injection failure to "
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityTrace.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityTrace.java
new file mode 100644
index 0000000..0c03877
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityTrace.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.accessibility;
+
+/**
+ * Interface to log accessibility trace.
+ */
+public interface AccessibilityTrace {
+    /**
+     * Whether the trace is enabled.
+     */
+    boolean isA11yTracingEnabled();
+
+    /**
+     * Log one trace entry.
+     * @param where A string to identify this log entry, which can be used to filter/search
+     *        through the tracing file.
+     */
+    void logTrace(String where);
+
+    /**
+     * Log one trace entry.
+     * @param where A string to identify this log entry, which can be used to filter/search
+     *        through the tracing file.
+     * @param callingParams The parameters for the method to be logged.
+     */
+    void logTrace(String where, String callingParams);
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
index 4473754..9547280 100644
--- a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
@@ -53,6 +53,8 @@
 
     private AbstractAccessibilityServiceConnection.SystemSupport mSystemSupport;
 
+    private AccessibilityTrace mTrace;
+
     private int mUiAutomationFlags;
 
     UiAutomationManager(Object lock) {
@@ -89,6 +91,7 @@
             int id, Handler mainHandler,
             AccessibilitySecurityPolicy securityPolicy,
             AbstractAccessibilityServiceConnection.SystemSupport systemSupport,
+            AccessibilityTrace trace,
             WindowManagerInternal windowManagerInternal,
             SystemActionPerformer systemActionPerformer,
             AccessibilityWindowManager awm, int flags) {
@@ -111,13 +114,14 @@
 
             mUiAutomationFlags = flags;
             mSystemSupport = systemSupport;
+            mTrace = trace;
             // Ignore registering UiAutomation if it is not allowed to use the accessibility
             // subsystem.
             if (!useAccessibility()) {
                 return;
             }
             mUiAutomationService = new UiAutomationService(context, accessibilityServiceInfo, id,
-                    mainHandler, mLock, securityPolicy, systemSupport, windowManagerInternal,
+                    mainHandler, mLock, securityPolicy, systemSupport, trace, windowManagerInternal,
                     systemActionPerformer, awm);
             mUiAutomationServiceOwner = owner;
             mUiAutomationServiceInfo = accessibilityServiceInfo;
@@ -239,11 +243,12 @@
         UiAutomationService(Context context, AccessibilityServiceInfo accessibilityServiceInfo,
                 int id, Handler mainHandler, Object lock,
                 AccessibilitySecurityPolicy securityPolicy,
-                SystemSupport systemSupport, WindowManagerInternal windowManagerInternal,
+                SystemSupport systemSupport, AccessibilityTrace trace,
+                WindowManagerInternal windowManagerInternal,
                 SystemActionPerformer systemActionPerformer, AccessibilityWindowManager awm) {
             super(context, COMPONENT_NAME, accessibilityServiceInfo, id, mainHandler, lock,
-                    securityPolicy, systemSupport, windowManagerInternal, systemActionPerformer,
-                    awm);
+                    securityPolicy, systemSupport, trace, windowManagerInternal,
+                    systemActionPerformer, awm);
             mMainHandler = mainHandler;
         }
 
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/GesturesObserver.java b/services/accessibility/java/com/android/server/accessibility/magnification/GesturesObserver.java
index feed18d..3d8f5173 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/GesturesObserver.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/GesturesObserver.java
@@ -98,8 +98,7 @@
         }
         mProcessMotionEvent = true;
         for (int i = 0; i < mGestureMatchers.size(); i++) {
-            final GestureMatcher matcher =
-                    mGestureMatchers.get(i);
+            final GestureMatcher matcher = mGestureMatchers.get(i);
             matcher.onMotionEvent(event, rawEvent, policyFlags);
             if (matcher.getState() == GestureMatcher.STATE_GESTURE_COMPLETED) {
                 clear();
@@ -128,7 +127,10 @@
             MotionEvent rawEvent, int policyFlags) {
         if (state == GestureMatcher.STATE_GESTURE_COMPLETED) {
             mListener.onGestureCompleted(gestureId, event, rawEvent, policyFlags);
-            //Clear the states in onMotionEvent().
+            // Ideally we clear the states in onMotionEvent(), this case is for hold gestures.
+            // If we clear before processing up event , then MultiTap matcher cancels the gesture
+            // due to incorrect state. It ends up listener#onGestureCancelled is called even
+            // the gesture is detected.
             if (!mProcessMotionEvent) {
                 clear();
             }
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureMatcher.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureMatcher.java
index 7a4d9e3..570e0ce 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureMatcher.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureMatcher.java
@@ -33,7 +33,7 @@
 class MagnificationGestureMatcher {
 
     private static final int GESTURE_BASE = 100;
-    public static final int GESTURE_TWO_FINGER_DOWN = GESTURE_BASE + 1;
+    public static final int GESTURE_TWO_FINGERS_DOWN_OR_SWIPE = GESTURE_BASE + 1;
     public static final int GESTURE_SWIPE = GESTURE_BASE + 2;
     public static final int GESTURE_SINGLE_TAP = GESTURE_BASE + 3;
     public static final int GESTURE_SINGLE_TAP_AND_HOLD = GESTURE_BASE + 4;
@@ -41,7 +41,7 @@
     public static final int GESTURE_TRIPLE_TAP_AND_HOLD = GESTURE_BASE + 6;
 
     @IntDef(prefix = {"GESTURE_MAGNIFICATION_"}, value = {
-            GESTURE_TWO_FINGER_DOWN,
+            GESTURE_TWO_FINGERS_DOWN_OR_SWIPE,
             GESTURE_SWIPE
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -57,8 +57,8 @@
         switch (gestureId) {
             case GESTURE_SWIPE:
                 return "GESTURE_SWIPE";
-            case GESTURE_TWO_FINGER_DOWN:
-                return "GESTURE_TWO_FINGER_DOWN";
+            case GESTURE_TWO_FINGERS_DOWN_OR_SWIPE:
+                return "GESTURE_TWO_FINGERS_DOWN_OR_SWIPE";
             case GESTURE_SINGLE_TAP:
                 return "GESTURE_SINGLE_TAP";
             case GESTURE_SINGLE_TAP_AND_HOLD:
@@ -71,6 +71,12 @@
         return "none";
     }
 
+    /**
+     * @param context
+     * @return the duration in milliseconds between the first tap's down event and
+     * the second tap's down event to be considered that the user is going to performing
+     *  panning/scaling gesture.
+     */
     static int getMagnificationMultiTapTimeout(Context context) {
         return ViewConfiguration.getDoubleTapTimeout() + context.getResources().getInteger(
                 R.integer.config_screen_magnification_multi_tap_adjustment);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java
index a209086..085c343 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGesturesObserver.java
@@ -65,7 +65,7 @@
          *                  the last event before timeout.
          *
          * @see MagnificationGestureMatcher#GESTURE_SWIPE
-         * @see MagnificationGestureMatcher#GESTURE_TWO_FINGER_DOWN
+         * @see MagnificationGestureMatcher#GESTURE_TWO_FINGERS_DOWN_OR_SWIPE
          */
         void onGestureCompleted(@GestureId int gestureId, long lastDownEventTime,
                 List<MotionEventInfo> delayedEventQueue, MotionEvent event);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/SimpleSwipe.java b/services/accessibility/java/com/android/server/accessibility/magnification/SimpleSwipe.java
index cd5061f..fa15ac1 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/SimpleSwipe.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/SimpleSwipe.java
@@ -49,6 +49,11 @@
     }
 
     @Override
+    protected void onPointerDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        cancelGesture(event, rawEvent, policyFlags);
+    }
+
+    @Override
     protected void onMove(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
         if (gestureMatched(event, rawEvent, policyFlags)) {
             completeGesture(event, rawEvent, policyFlags);
@@ -65,7 +70,7 @@
     }
 
     private boolean gestureMatched(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
-        return mLastDown != null && (distance(mLastDown, event) >= mSwipeMinDistance);
+        return mLastDown != null && (distance(mLastDown, event) > mSwipeMinDistance);
     }
 
     @Override
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/TwoFingersDown.java b/services/accessibility/java/com/android/server/accessibility/magnification/TwoFingersDown.java
deleted file mode 100644
index 173a5b8..0000000
--- a/services/accessibility/java/com/android/server/accessibility/magnification/TwoFingersDown.java
+++ /dev/null
@@ -1,74 +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.accessibility.magnification;
-
-import android.content.Context;
-import android.os.Handler;
-import android.view.MotionEvent;
-
-import com.android.server.accessibility.gestures.GestureMatcher;
-
-/**
- *
- * This class is responsible for matching two fingers down gestures. The gesture matching
- * result is determined in a duration.
- */
-final class TwoFingersDown extends GestureMatcher {
-
-    private MotionEvent mLastDown;
-    private final int mDetectionDurationMillis;
-
-    TwoFingersDown(Context context) {
-        super(MagnificationGestureMatcher.GESTURE_TWO_FINGER_DOWN,
-                new Handler(context.getMainLooper()), null);
-        mDetectionDurationMillis = MagnificationGestureMatcher.getMagnificationMultiTapTimeout(
-                context);
-    }
-
-    @Override
-    protected void onDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
-        mLastDown = MotionEvent.obtain(event);
-        cancelAfter(mDetectionDurationMillis, event, rawEvent, policyFlags);
-    }
-
-    @Override
-    protected void onPointerDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
-        if (mLastDown == null) {
-            cancelGesture(event, rawEvent, policyFlags);
-        }
-        completeGesture(event, rawEvent, policyFlags);
-    }
-
-    @Override
-    protected void onUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
-        cancelGesture(event, rawEvent, policyFlags);
-    }
-
-    @Override
-    public void clear() {
-        if (mLastDown != null) {
-            mLastDown.recycle();
-            mLastDown = null;
-        }
-        super.clear();
-    }
-
-    @Override
-    protected String getGestureName() {
-        return this.getClass().getSimpleName();
-    }
-}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/TwoFingersDownOrSwipe.java b/services/accessibility/java/com/android/server/accessibility/magnification/TwoFingersDownOrSwipe.java
new file mode 100644
index 0000000..1742bd4
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/TwoFingersDownOrSwipe.java
@@ -0,0 +1,123 @@
+/*
+ * 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.accessibility.magnification;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.Handler;
+import android.util.MathUtils;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+import com.android.server.accessibility.gestures.GestureMatcher;
+
+/**
+ * This class is responsible for detecting that the user is using two fingers to perform
+ * swiping gestures or just stay pressed on the screen. The gesture matching result is determined
+ * in a duration.
+ */
+final class TwoFingersDownOrSwipe extends GestureMatcher {
+
+    private final int mDoubleTapTimeout;
+    private final int mDetectionDurationMillis;
+    private final int mSwipeMinDistance;
+    private MotionEvent mFirstPointerDown;
+    private MotionEvent mSecondPointerDown;
+
+    TwoFingersDownOrSwipe(Context context) {
+        super(MagnificationGestureMatcher.GESTURE_TWO_FINGERS_DOWN_OR_SWIPE,
+                new Handler(context.getMainLooper()), null);
+        mDetectionDurationMillis = MagnificationGestureMatcher.getMagnificationMultiTapTimeout(
+                context);
+        mDoubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();
+        mSwipeMinDistance = ViewConfiguration.get(context).getScaledTouchSlop();
+
+    }
+
+    @Override
+    protected void onDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        mFirstPointerDown = MotionEvent.obtain(event);
+        cancelAfter(mDetectionDurationMillis, event, rawEvent, policyFlags);
+    }
+
+    @Override
+    protected void onPointerDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        if (mFirstPointerDown == null) {
+            cancelGesture(event, rawEvent, policyFlags);
+        }
+        if (event.getPointerCount() == 2) {
+            mSecondPointerDown = MotionEvent.obtain(event);
+            completeAfter(mDoubleTapTimeout, event, rawEvent, policyFlags);
+        } else {
+            cancelGesture(event, rawEvent, policyFlags);
+        }
+    }
+
+    @Override
+    protected void onMove(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        if (mFirstPointerDown == null || mSecondPointerDown == null) {
+            return;
+        }
+        if (distance(mFirstPointerDown, /* move */ event) > mSwipeMinDistance) {
+            completeGesture(event, rawEvent, policyFlags);
+            return;
+        }
+        if (distance(mSecondPointerDown, /* move */ event) > mSwipeMinDistance) {
+            // The second pointer is swiping.
+            completeGesture(event, rawEvent, policyFlags);
+        }
+    }
+
+    @Override
+    protected void onPointerUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        cancelGesture(event, rawEvent, policyFlags);
+    }
+
+    @Override
+    protected void onUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        cancelGesture(event, rawEvent, policyFlags);
+    }
+
+    @Override
+    public void clear() {
+        if (mFirstPointerDown != null) {
+            mFirstPointerDown.recycle();
+            mFirstPointerDown = null;
+        }
+        if (mSecondPointerDown != null) {
+            mSecondPointerDown.recycle();
+            mSecondPointerDown = null;
+        }
+        super.clear();
+    }
+
+    @Override
+    protected String getGestureName() {
+        return this.getClass().getSimpleName();
+    }
+
+    private static double distance(@NonNull MotionEvent downEvent, @NonNull MotionEvent moveEvent) {
+        final int downActionIndex = downEvent.getActionIndex();
+        final int downPointerId = downEvent.getPointerId(downActionIndex);
+        final int moveActionIndex = moveEvent.findPointerIndex(downPointerId);
+        if (moveActionIndex < 0) {
+            return -1;
+        }
+        return MathUtils.dist(downEvent.getX(downActionIndex), downEvent.getY(downActionIndex),
+                moveEvent.getX(moveActionIndex), moveEvent.getY(moveActionIndex));
+    }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
index 55a911e..fa34062 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
@@ -323,7 +323,7 @@
      * manipulate the window magnifier or want to interact with current UI. The rule of leaving
      * this state is as follows:
      * <ol>
-     *   <li> If {@link MagnificationGestureMatcher#GESTURE_TWO_FINGER_DOWN} is detected,
+     *   <li> If {@link MagnificationGestureMatcher#GESTURE_TWO_FINGERS_DOWN_OR_SWIPE} is detected,
      *   {@link State} will be transited to {@link PanningScalingGestureState}.</li>
      *   <li> If other gesture is detected and the last motion event is neither ACTION_UP nor
      *   ACTION_CANCEL.
@@ -357,7 +357,7 @@
                     new SimpleSwipe(context),
                     multiTap,
                     multiTapAndHold,
-                    new TwoFingersDown(context));
+                    new TwoFingersDownOrSwipe(context));
         }
 
         @Override
@@ -399,7 +399,7 @@
                 Slog.d(mLogTag,
                         "onGestureDetected : delayedEventQueue = " + delayedEventQueue);
             }
-            if (gestureId == MagnificationGestureMatcher.GESTURE_TWO_FINGER_DOWN
+            if (gestureId == MagnificationGestureMatcher.GESTURE_TWO_FINGERS_DOWN_OR_SWIPE
                     && mWindowMagnificationMgr.pointersInWindow(mDisplayId, motionEvent) > 0) {
                 transitionTo(mObservePanningScalingState);
             } else if (gestureId == MagnificationGestureMatcher.GESTURE_TRIPLE_TAP) {
diff --git a/services/api/Android.bp b/services/api/Android.bp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/services/api/Android.bp
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 809304b..e251700 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -19,6 +19,7 @@
 import static android.content.Context.KEYGUARD_SERVICE;
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.res.Resources.ID_NULL;
 
 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 
@@ -137,7 +138,6 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
@@ -181,9 +181,6 @@
             }
 
             switch (action) {
-                case Intent.ACTION_CONFIGURATION_CHANGED:
-                    onConfigurationChanged();
-                    break;
                 case Intent.ACTION_MANAGED_PROFILE_AVAILABLE:
                 case Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE:
                     synchronized (mLock) {
@@ -243,8 +240,6 @@
     private Handler mSaveStateHandler;
     private Handler mCallbackHandler;
 
-    private Locale mLocale;
-
     private final SparseIntArray mNextAppWidgetIds = new SparseIntArray();
 
     private boolean mSafeMode;
@@ -290,13 +285,6 @@
     }
 
     private void registerBroadcastReceiver() {
-        // Register for configuration changes so we can update the names
-        // of the widgets when the locale changes.
-        IntentFilter configFilter = new IntentFilter();
-        configFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
-        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
-                configFilter, null, null);
-
         // Register for broadcasts about package install, etc., so we can
         // update the provider list.
         IntentFilter packageFilter = new IntentFilter();
@@ -338,62 +326,6 @@
         mSafeMode = safeMode;
     }
 
-    private void onConfigurationChanged() {
-        if (DEBUG) {
-            Slog.i(TAG, "onConfigurationChanged()");
-        }
-
-        Locale revised = Locale.getDefault();
-        if (revised == null || mLocale == null || !revised.equals(mLocale)) {
-            mLocale = revised;
-
-            synchronized (mLock) {
-                SparseIntArray changedGroups = null;
-
-                // Note: updateProvidersForPackageLocked() may remove providers, so we must copy the
-                // list of installed providers and skip providers that we don't need to update.
-                // Also note that remove the provider does not clear the Provider component data.
-                ArrayList<Provider> installedProviders = new ArrayList<>(mProviders);
-                HashSet<ProviderId> removedProviders = new HashSet<>();
-
-                int N = installedProviders.size();
-                for (int i = N - 1; i >= 0; i--) {
-                    Provider provider = installedProviders.get(i);
-
-                    final int userId = provider.getUserId();
-                    if (!mUserManager.isUserUnlockingOrUnlocked(userId) ||
-                            isProfileWithLockedParent(userId)) {
-                        continue;
-                    }
-                    ensureGroupStateLoadedLocked(userId);
-
-                    if (!removedProviders.contains(provider.id)) {
-                        final boolean changed = updateProvidersForPackageLocked(
-                                provider.id.componentName.getPackageName(),
-                                provider.getUserId(), removedProviders);
-
-                        if (changed) {
-                            if (changedGroups == null) {
-                                changedGroups = new SparseIntArray();
-                            }
-                            final int groupId = mSecurityPolicy.getGroupParent(
-                                    provider.getUserId());
-                            changedGroups.put(groupId, groupId);
-                        }
-                    }
-                }
-
-                if (changedGroups != null) {
-                    final int groupCount = changedGroups.size();
-                    for (int i = 0; i < groupCount; i++) {
-                        final int groupId = changedGroups.get(i);
-                        saveGroupStateAsync(groupId);
-                    }
-                }
-            }
-        }
-    }
-
     private void onPackageBroadcastReceived(Intent intent, int userId) {
         final String action = intent.getAction();
         boolean added = false;
@@ -2647,9 +2579,9 @@
             info.updatePeriodMillis = sa.getInt(
                     com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0);
             info.initialLayout = sa.getResourceId(
-                    com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, 0);
+                    com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, ID_NULL);
             info.initialKeyguardLayout = sa.getResourceId(com.android.internal.R.styleable.
-                    AppWidgetProviderInfo_initialKeyguardLayout, 0);
+                    AppWidgetProviderInfo_initialKeyguardLayout, ID_NULL);
 
             String className = sa
                     .getString(com.android.internal.R.styleable.AppWidgetProviderInfo_configure);
@@ -2660,11 +2592,12 @@
             info.label = activityInfo.loadLabel(pm).toString();
             info.icon = activityInfo.getIconResource();
             info.previewImage = sa.getResourceId(
-                    com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, 0);
+                    com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, ID_NULL);
             info.previewLayout = sa.getResourceId(
-                    com.android.internal.R.styleable.AppWidgetProviderInfo_previewLayout, 0);
+                    com.android.internal.R.styleable.AppWidgetProviderInfo_previewLayout, ID_NULL);
             info.autoAdvanceViewId = sa.getResourceId(
-                    com.android.internal.R.styleable.AppWidgetProviderInfo_autoAdvanceViewId, -1);
+                    com.android.internal.R.styleable.AppWidgetProviderInfo_autoAdvanceViewId,
+                    View.NO_ID);
             info.resizeMode = sa.getInt(
                     com.android.internal.R.styleable.AppWidgetProviderInfo_resizeMode,
                     AppWidgetProviderInfo.RESIZE_NONE);
@@ -2673,9 +2606,8 @@
                     AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN);
             info.widgetFeatures = sa.getInt(
                     com.android.internal.R.styleable.AppWidgetProviderInfo_widgetFeatures, 0);
-            info.descriptionResource = sa.getResourceId(
-                    com.android.internal.R.styleable.AppWidgetProviderInfo_description,
-                    Resources.ID_NULL);
+            info.descriptionRes = sa.getResourceId(
+                    com.android.internal.R.styleable.AppWidgetProviderInfo_description, ID_NULL);
             sa.recycle();
             return info;
         } catch (IOException | PackageManager.NameNotFoundException | XmlPullParserException e) {
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 6c30999..38275f7 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1245,10 +1245,9 @@
 
     @Override
     public IRestoreSession beginRestoreSessionForUser(
-            int userId, String packageName, String transportID,
-            @OperationType int operationType) throws RemoteException {
+            int userId, String packageName, String transportID) throws RemoteException {
         return isUserReadyForBackup(userId)
-                ? beginRestoreSession(userId, packageName, transportID, operationType) : null;
+                ? beginRestoreSession(userId, packageName, transportID) : null;
     }
 
     /**
@@ -1257,15 +1256,13 @@
      */
     @Nullable
     public IRestoreSession beginRestoreSession(
-            @UserIdInt int userId, String packageName, String transportName,
-            @OperationType int operationType) {
+            @UserIdInt int userId, String packageName, String transportName) {
         UserBackupManagerService userBackupManagerService =
                 getServiceForUserIfCallerHasPermission(userId, "beginRestoreSession()");
 
         return userBackupManagerService == null
                 ? null
-                : userBackupManagerService.beginRestoreSession(packageName, transportName,
-                        operationType);
+                : userBackupManagerService.beginRestoreSession(packageName, transportName);
     }
 
     @Override
@@ -1350,15 +1347,15 @@
         if (!isUserReadyForBackup(userId)) {
             return BackupManager.ERROR_BACKUP_NOT_ALLOWED;
         }
-        return requestBackup(userId, packages, observer, monitor, flags, OperationType.BACKUP);
+        return requestBackup(userId, packages, observer, monitor, flags);
     }
 
     @Override
     public int requestBackup(String[] packages, IBackupObserver observer,
-            IBackupManagerMonitor monitor, int flags, @OperationType int operationType)
+            IBackupManagerMonitor monitor, int flags)
             throws RemoteException {
         return requestBackup(binderGetCallingUserId(), packages,
-                observer, monitor, flags, operationType);
+                observer, monitor, flags);
     }
 
     /**
@@ -1370,15 +1367,13 @@
             String[] packages,
             IBackupObserver observer,
             IBackupManagerMonitor monitor,
-            int flags,
-            @OperationType int operationType) {
+            int flags) {
         UserBackupManagerService userBackupManagerService =
                 getServiceForUserIfCallerHasPermission(userId, "requestBackup()");
 
         return userBackupManagerService == null
                 ? BackupManager.ERROR_BACKUP_NOT_ALLOWED
-                : userBackupManagerService.requestBackup(packages, observer, monitor, flags,
-                        operationType);
+                : userBackupManagerService.requestBackup(packages, observer, monitor, flags);
     }
 
     @Override
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 136cd22f..9ee0159 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -96,6 +96,7 @@
 import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.EventLog;
+import android.util.FeatureFlagUtils;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -127,6 +128,7 @@
 import com.android.server.backup.restore.ActiveRestoreSession;
 import com.android.server.backup.restore.PerformUnifiedRestoreTask;
 import com.android.server.backup.transport.TransportClient;
+import com.android.server.backup.transport.TransportNotAvailableException;
 import com.android.server.backup.transport.TransportNotRegisteredException;
 import com.android.server.backup.utils.BackupEligibilityRules;
 import com.android.server.backup.utils.BackupManagerMonitorUtils;
@@ -1860,19 +1862,10 @@
 
     /**
      * Requests a backup for the inputted {@code packages} with a specified {@link
-     * IBackupManagerMonitor}.
-     */
-    public int requestBackup(String[] packages, IBackupObserver observer,
-            IBackupManagerMonitor monitor, int flags) {
-        return requestBackup(packages, observer, monitor, flags, OperationType.BACKUP);
-    }
-
-    /**
-     * Requests a backup for the inputted {@code packages} with a specified {@link
      * IBackupManagerMonitor} and {@link OperationType}.
      */
     public int requestBackup(String[] packages, IBackupObserver observer,
-            IBackupManagerMonitor monitor, int flags, @OperationType int operationType) {
+            IBackupManagerMonitor monitor, int flags) {
         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "requestBackup");
 
         if (packages == null || packages.length < 1) {
@@ -1903,13 +1896,16 @@
 
         final TransportClient transportClient;
         final String transportDirName;
+        int operationType;
         try {
             transportDirName =
                     mTransportManager.getTransportDirName(
                             mTransportManager.getCurrentTransportName());
             transportClient =
                     mTransportManager.getCurrentTransportClientOrThrow("BMS.requestBackup()");
-        } catch (TransportNotRegisteredException e) {
+            operationType = getOperationTypeFromTransport(transportClient);
+        } catch (TransportNotRegisteredException | TransportNotAvailableException
+                | RemoteException e) {
             BackupObserverUtils.sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED);
             monitor = BackupManagerMonitorUtils.monitorEvent(monitor,
                     BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_IS_NULL,
@@ -4024,15 +4020,13 @@
     }
 
     /** Hand off a restore session. */
-    public IRestoreSession beginRestoreSession(String packageName, String transport,
-            @OperationType int operationType) {
+    public IRestoreSession beginRestoreSession(String packageName, String transport) {
         if (DEBUG) {
             Slog.v(
                     TAG,
                     addUserIdToLogMessage(
                             mUserId,
-                            "beginRestoreSession: pkg=" + packageName + " transport=" + transport
-                                + "operationType=" + operationType));
+                            "beginRestoreSession: pkg=" + packageName + " transport=" + transport));
         }
 
         boolean needPermission = true;
@@ -4073,6 +4067,17 @@
             }
         }
 
+        int operationType;
+        try {
+            operationType = getOperationTypeFromTransport(
+                    mTransportManager.getTransportClientOrThrow(transport, /* caller */
+                            "BMS.beginRestoreSession"));
+        } catch (TransportNotAvailableException | TransportNotRegisteredException
+                | RemoteException e) {
+            Slog.w(TAG, "Failed to get operation type from transport: " + e);
+            return null;
+        }
+
         synchronized (this) {
             if (mActiveRestoreSession != null) {
                 Slog.i(
@@ -4356,6 +4361,34 @@
         }
     }
 
+    @VisibleForTesting
+    @OperationType int getOperationTypeFromTransport(TransportClient transportClient)
+            throws TransportNotAvailableException, RemoteException {
+        if (!shouldUseNewBackupEligibilityRules()) {
+            // Return the default to stick to the legacy behaviour.
+            return OperationType.BACKUP;
+        }
+
+        long oldCallingId = Binder.clearCallingIdentity();
+        try {
+            IBackupTransport transport = transportClient.connectOrThrow(
+                    /* caller */ "BMS.getOperationTypeFromTransport");
+            if ((transport.getTransportFlags() & BackupAgent.FLAG_DEVICE_TO_DEVICE_TRANSFER) != 0) {
+                return OperationType.MIGRATION;
+            } else {
+                return OperationType.BACKUP;
+            }
+        } finally {
+            Binder.restoreCallingIdentity(oldCallingId);
+        }
+    }
+
+    @VisibleForTesting
+    boolean shouldUseNewBackupEligibilityRules() {
+        return FeatureFlagUtils.isEnabled(mContext,
+                FeatureFlagUtils.SETTINGS_USE_NEW_BACKUP_ELIGIBILITY_RULES);
+    }
+
     private static String addUserIdToLogMessage(int userId, String message) {
         return "[UserID:" + userId + "] " + message;
     }
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 01055be..21cae45 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -142,18 +142,13 @@
 import java.util.concurrent.ConcurrentMap;
 import java.util.function.Function;
 
-//TODO onStop schedule unbind in 5 seconds
-//TODO make sure APIs are only callable from currently focused app
-//TODO schedule stopScan on activity destroy(except if configuration change)
-//TODO on associate called again after configuration change -> replace old callback with new
-//TODO avoid leaking calling activity in IFindDeviceCallback (see PrintManager#print for example)
 /** @hide */
 @SuppressLint("LongLogTag")
 public class CompanionDeviceManagerService extends SystemService implements Binder.DeathRecipient {
 
     private static final ComponentName SERVICE_TO_BIND_TO = ComponentName.createRelative(
             CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME,
-            ".DeviceDiscoveryService");
+            ".CompanionDeviceDiscoveryService");
 
     private static final long DEVICE_DISAPPEARED_TIMEOUT_MS = 10 * 1000;
     private static final long DEVICE_DISAPPEARED_UNBIND_TIMEOUT_MS = 10 * 60 * 1000;
@@ -747,6 +742,15 @@
                 }
             }
         }
+
+        if (association.isNotifyOnDeviceNearby()) {
+            ServiceConnector<ICompanionDeviceService> serviceConnector =
+                    mDeviceListenerServiceConnectors.forUser(association.getUserId())
+                            .get(association.getPackageName());
+            if (serviceConnector != null) {
+                serviceConnector.unbind();
+            }
+        }
     }
 
     private void updateSpecialAccessPermissionForAssociatedPackage(Association association) {
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 0be485b..02930dc 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -88,7 +88,6 @@
 import com.android.internal.infra.GlobalWhitelistState;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.util.DumpUtils;
-import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
 import com.android.server.infra.AbstractMasterSystemService;
 import com.android.server.infra.FrameworkResourcesServiceNameResolver;
@@ -101,6 +100,7 @@
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
@@ -602,10 +602,11 @@
 
         @Override
         public void startSession(@NonNull IBinder activityToken,
-                @NonNull ComponentName componentName, int sessionId, int flags,
-                @NonNull IResultReceiver result) {
-            Preconditions.checkNotNull(activityToken);
-            Preconditions.checkNotNull(sessionId);
+                @NonNull IBinder shareableActivityToken, @NonNull ComponentName componentName,
+                int sessionId, int flags, @NonNull IResultReceiver result) {
+            Objects.requireNonNull(activityToken);
+            Objects.requireNonNull(shareableActivityToken);
+            Objects.requireNonNull(sessionId);
             final int userId = UserHandle.getCallingUserId();
 
             final ActivityPresentationInfo activityPresentationInfo = getAmInternal()
@@ -617,14 +618,14 @@
                     setClientState(result, STATE_DISABLED, /* binder= */ null);
                     return;
                 }
-                service.startSessionLocked(activityToken, activityPresentationInfo, sessionId,
-                        Binder.getCallingUid(), flags, result);
+                service.startSessionLocked(activityToken, shareableActivityToken,
+                        activityPresentationInfo, sessionId, Binder.getCallingUid(), flags, result);
             }
         }
 
         @Override
         public void finishSession(int sessionId) {
-            Preconditions.checkNotNull(sessionId);
+            Objects.requireNonNull(sessionId);
             final int userId = UserHandle.getCallingUserId();
 
             synchronized (mLock) {
@@ -650,7 +651,7 @@
 
         @Override
         public void removeData(@NonNull DataRemovalRequest request) {
-            Preconditions.checkNotNull(request);
+            Objects.requireNonNull(request);
             assertCalledByPackageOwner(request.getPackageName());
 
             final int userId = UserHandle.getCallingUserId();
@@ -663,8 +664,8 @@
         @Override
         public void shareData(@NonNull DataShareRequest request,
                 @NonNull IDataShareWriteAdapter clientAdapter) {
-            Preconditions.checkNotNull(request);
-            Preconditions.checkNotNull(clientAdapter);
+            Objects.requireNonNull(request);
+            Objects.requireNonNull(clientAdapter);
 
             assertCalledByPackageOwner(request.getPackageName());
 
@@ -795,6 +796,23 @@
             new ContentCaptureManagerServiceShellCommand(ContentCaptureManagerService.this).exec(
                     this, in, out, err, args, callback, resultReceiver);
         }
+
+        @Override
+        public void resetTemporaryService(@UserIdInt int userId) {
+            ContentCaptureManagerService.this.resetTemporaryService(userId);
+        }
+
+        @Override
+        public void setTemporaryService(
+                @UserIdInt int userId, @NonNull String serviceName, int duration) {
+            ContentCaptureManagerService.this.setTemporaryService(
+                    userId, serviceName, duration);
+        }
+
+        @Override
+        public void setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
+            ContentCaptureManagerService.this.setDefaultServiceEnabled(userId, enabled);
+        }
     }
 
     private final class LocalService extends ContentCaptureManagerInternal {
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index ea68e19..53cdc33 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -35,6 +35,7 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManagerInternal;
+import android.app.assist.ActivityId;
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
 import android.content.ComponentName;
@@ -241,6 +242,7 @@
 
     @GuardedBy("mLock")
     public void startSessionLocked(@NonNull IBinder activityToken,
+            @NonNull IBinder shareableActivityToken,
             @NonNull ActivityPresentationInfo activityPresentationInfo, int sessionId, int uid,
             int flags, @NonNull IResultReceiver clientReceiver) {
         if (activityPresentationInfo == null) {
@@ -340,8 +342,8 @@
         mRemoteService.ensureBoundLocked();
 
         final ContentCaptureServerSession newSession = new ContentCaptureServerSession(mLock,
-                activityToken, this, componentName, clientReceiver, taskId, displayId, sessionId,
-                uid, flags);
+                activityToken, new ActivityId(taskId, shareableActivityToken), this, componentName,
+                clientReceiver, taskId, displayId, sessionId, uid, flags);
         if (mMaster.verbose) {
             Slog.v(TAG, "startSession(): new session for "
                     + ComponentName.flattenToShortString(componentName) + " and id " + sessionId);
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
index 06ab426..9f3045e 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
@@ -25,6 +25,7 @@
 import static android.view.contentcapture.ContentCaptureSession.STATE_SERVICE_UPDATING;
 
 import android.annotation.NonNull;
+import android.app.assist.ActivityId;
 import android.content.ComponentName;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -75,9 +76,9 @@
     public final ComponentName appComponentName;
 
     ContentCaptureServerSession(@NonNull Object lock, @NonNull IBinder activityToken,
-            @NonNull ContentCapturePerUserService service, @NonNull ComponentName appComponentName,
-            @NonNull IResultReceiver sessionStateReceiver, int taskId, int displayId, int sessionId,
-            int uid, int flags) {
+            @NonNull ActivityId activityId, @NonNull ContentCapturePerUserService service,
+            @NonNull ComponentName appComponentName, @NonNull IResultReceiver sessionStateReceiver,
+            int taskId, int displayId, int sessionId, int uid, int flags) {
         Preconditions.checkArgument(sessionId != NO_SESSION_ID);
         mLock = lock;
         mActivityToken = activityToken;
@@ -86,7 +87,7 @@
         mId = sessionId;
         mUid = uid;
         mContentCaptureContext = new ContentCaptureContext(/* clientContext= */ null,
-                appComponentName, taskId, displayId, flags);
+                activityId, appComponentName, displayId, flags);
         mSessionStateReceiver = sessionStateReceiver;
         try {
             sessionStateReceiver.asBinder().linkToDeath(() -> onClientDeath(), 0);
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
index 00c91fe..57c643b 100644
--- a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
@@ -21,6 +21,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.contentsuggestions.ClassificationsRequest;
 import android.app.contentsuggestions.ContentSuggestionsManager;
 import android.app.contentsuggestions.IClassificationsCallback;
@@ -253,6 +254,23 @@
             receiver.send(isDisabled ? 0 : 1, null);
         }
 
+        @Override
+        public void resetTemporaryService(@UserIdInt int userId) {
+            ContentSuggestionsManagerService.this.resetTemporaryService(userId);
+        }
+
+        @Override
+        public void setTemporaryService(
+                @UserIdInt int userId, @NonNull String serviceName, int duration) {
+            ContentSuggestionsManagerService.this.setTemporaryService(
+                    userId, serviceName, duration);
+        }
+
+        @Override
+        public void setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
+            ContentSuggestionsManagerService.this.setDefaultServiceEnabled(userId, enabled);
+        }
+
         public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
                 @Nullable FileDescriptor err,
                 @NonNull String[] args, @Nullable ShellCallback callback,
diff --git a/services/core/Android.bp b/services/core/Android.bp
index b67bdc2..99ce2db 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -97,6 +97,7 @@
         ":platform-compat-config",
         ":platform-compat-overrides",
         ":display-device-config",
+        ":display-layout-config",
         ":cec-config",
         ":device-state-config",
         "java/com/android/server/EventLogTags.logtags",
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index f4138d1..986e2acf 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -44,6 +44,7 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE;
@@ -91,7 +92,6 @@
 import android.net.IDnsResolver;
 import android.net.INetd;
 import android.net.INetworkActivityListener;
-import android.net.INetworkManagementEventObserver;
 import android.net.INetworkMonitor;
 import android.net.INetworkMonitorCallbacks;
 import android.net.INetworkPolicyListener;
@@ -120,6 +120,7 @@
 import android.net.NetworkStack;
 import android.net.NetworkStackClient;
 import android.net.NetworkState;
+import android.net.NetworkStateSnapshot;
 import android.net.NetworkTestResultParcelable;
 import android.net.NetworkUtils;
 import android.net.NetworkWatchlistManager;
@@ -141,10 +142,13 @@
 import android.net.Uri;
 import android.net.VpnManager;
 import android.net.VpnTransportInfo;
-import android.net.metrics.INetdEventListener;
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.NetworkEvent;
 import android.net.netlink.InetDiagMessage;
+import android.net.resolv.aidl.DnsHealthEventParcel;
+import android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener;
+import android.net.resolv.aidl.Nat64PrefixEventParcel;
+import android.net.resolv.aidl.PrivateDnsValidationEventParcel;
 import android.net.shared.PrivateDnsConfig;
 import android.net.util.MultinetworkPolicyTracker;
 import android.net.util.NetdService;
@@ -155,7 +159,6 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
-import android.os.INetworkManagementService;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Messenger;
@@ -194,6 +197,7 @@
 import com.android.internal.util.LocationPermissionChecker;
 import com.android.internal.util.MessageUtils;
 import com.android.modules.utils.BasicShellCommandHandler;
+import com.android.net.module.util.BaseNetdUnsolicitedEventListener;
 import com.android.net.module.util.CollectionUtils;
 import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult;
 import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
@@ -214,7 +218,6 @@
 import com.android.server.connectivity.PermissionMonitor;
 import com.android.server.connectivity.ProxyTracker;
 import com.android.server.connectivity.QosCallbackTracker;
-import com.android.server.net.BaseNetworkObserver;
 import com.android.server.net.NetworkPolicyManagerInternal;
 import com.android.server.utils.PriorityDump;
 
@@ -324,7 +327,6 @@
     // 0 is full bad, 100 is full good
     private int mDefaultInetConditionPublished = 0;
 
-    private INetworkManagementService mNMS;
     @VisibleForTesting
     protected IDnsResolver mDnsResolver;
     @VisibleForTesting
@@ -332,6 +334,7 @@
     private INetworkStatsService mStatsService;
     private NetworkPolicyManager mPolicyManager;
     private NetworkPolicyManagerInternal mPolicyManagerInternal;
+    private final NetdCallback mNetdCallback;
 
     /**
      * TestNetworkService (lazily) created upon first usage. Locked to prevent creation of multiple
@@ -1039,15 +1042,14 @@
         }
     }
 
-    public ConnectivityService(Context context, INetworkManagementService netManager,
-            INetworkStatsService statsService) {
-        this(context, netManager, statsService, getDnsResolver(context), new IpConnectivityLog(),
+    public ConnectivityService(Context context, INetworkStatsService statsService) {
+        this(context, statsService, getDnsResolver(context), new IpConnectivityLog(),
                 NetdService.getInstance(), new Dependencies());
     }
 
     @VisibleForTesting
-    protected ConnectivityService(Context context, INetworkManagementService netManager,
-            INetworkStatsService statsService, IDnsResolver dnsresolver, IpConnectivityLog logger,
+    protected ConnectivityService(Context context, INetworkStatsService statsService,
+            IDnsResolver dnsresolver, IpConnectivityLog logger,
             INetd netd, Dependencies deps) {
         if (DBG) log("ConnectivityService starting up");
 
@@ -1094,7 +1096,6 @@
         // TODO: Consider making the timer customizable.
         mNascentDelayMs = DEFAULT_NASCENT_DELAY_MS;
 
-        mNMS = Objects.requireNonNull(netManager, "missing INetworkManagementService");
         mStatsService = Objects.requireNonNull(statsService, "missing INetworkStatsService");
         mPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
         mPolicyManagerInternal = Objects.requireNonNull(
@@ -1202,7 +1203,14 @@
         mUserAllContext.registerReceiver(mIntentReceiver, intentFilter,
                 null /* broadcastPermission */, mHandler);
 
-        mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mHandler, mNMS, mNetd);
+        mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mHandler, mNetd);
+
+        mNetdCallback = new NetdCallback();
+        try {
+            mNetd.registerUnsolicitedEventListener(mNetdCallback);
+        } catch (RemoteException | ServiceSpecificException e) {
+            loge("Error registering event listener :" + e);
+        }
 
         mSettingsObserver = new SettingsObserver(mContext, mHandler);
         registerSettingsCallbacks();
@@ -1229,18 +1237,19 @@
         mDnsManager = new DnsManager(mContext, mDnsResolver);
         registerPrivateDnsSettingsCallbacks();
 
-        mNoServiceNetwork =  new NetworkAgentInfo(null,
+        mNoServiceNetwork = new NetworkAgentInfo(null,
                 new Network(NO_SERVICE_NET_ID),
                 new NetworkInfo(TYPE_NONE, 0, "", ""),
                 new LinkProperties(), new NetworkCapabilities(), 0, mContext,
                 null, new NetworkAgentConfig(), this, null,
-                null, null, 0, INVALID_UID,
+                null, 0, INVALID_UID,
                 mQosCallbackTracker);
     }
 
     private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
         final NetworkCapabilities netCap = new NetworkCapabilities();
         netCap.addCapability(NET_CAPABILITY_INTERNET);
+        netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
         netCap.removeCapability(NET_CAPABILITY_NOT_VPN);
         netCap.setSingleUid(uid);
         return netCap;
@@ -1255,6 +1264,7 @@
             int transportType, NetworkRequest.Type type) {
         final NetworkCapabilities netCap = new NetworkCapabilities();
         netCap.addCapability(NET_CAPABILITY_INTERNET);
+        netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
         netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
         if (transportType > TYPE_NONE) {
             netCap.addTransportType(transportType);
@@ -1393,7 +1403,7 @@
         return null;
     }
 
-    private NetworkState getUnfilteredActiveNetworkState(int uid) {
+    private NetworkAgentInfo getNetworkAgentInfoForUid(int uid) {
         NetworkAgentInfo nai = getDefaultNetworkForUid(uid);
 
         final Network[] networks = getVpnUnderlyingNetworks(uid);
@@ -1409,12 +1419,7 @@
                 nai = null;
             }
         }
-
-        if (nai != null) {
-            return nai.getNetworkState();
-        } else {
-            return NetworkState.EMPTY;
-        }
+        return nai;
     }
 
     /**
@@ -1467,24 +1472,28 @@
                 "%s %d(%d) on netId %d", action, nri.mUid, requestId, net.getNetId()));
     }
 
-    private void filterNetworkInfo(@NonNull NetworkInfo networkInfo,
-            @NonNull NetworkCapabilities nc, int uid, boolean ignoreBlocked) {
-        if (isNetworkWithCapabilitiesBlocked(nc, uid, ignoreBlocked)) {
-            networkInfo.setDetailedState(DetailedState.BLOCKED, null, null);
-        }
-        networkInfo.setDetailedState(
-                getLegacyLockdownState(networkInfo.getDetailedState()),
-                "" /* reason */, null /* extraInfo */);
-    }
-
     /**
-     * Apply any relevant filters to {@link NetworkState} for the given UID. For
+     * Apply any relevant filters to the specified {@link NetworkInfo} for the given UID. For
      * example, this may mark the network as {@link DetailedState#BLOCKED} based
      * on {@link #isNetworkWithCapabilitiesBlocked}.
      */
-    private void filterNetworkStateForUid(NetworkState state, int uid, boolean ignoreBlocked) {
-        if (state == null || state.networkInfo == null || state.linkProperties == null) return;
-        filterNetworkInfo(state.networkInfo, state.networkCapabilities, uid, ignoreBlocked);
+    @NonNull
+    private NetworkInfo filterNetworkInfo(@NonNull NetworkInfo networkInfo, int type,
+            @NonNull NetworkCapabilities nc, int uid, boolean ignoreBlocked) {
+        NetworkInfo filtered = new NetworkInfo(networkInfo);
+        filtered.setType(type);
+        final DetailedState state = isNetworkWithCapabilitiesBlocked(nc, uid, ignoreBlocked)
+                ? DetailedState.BLOCKED
+                : filtered.getDetailedState();
+        filtered.setDetailedState(getLegacyLockdownState(state),
+                "" /* reason */, null /* extraInfo */);
+        return filtered;
+    }
+
+    private NetworkInfo getFilteredNetworkInfo(NetworkAgentInfo nai, int uid,
+            boolean ignoreBlocked) {
+        return filterNetworkInfo(nai.networkInfo, nai.networkInfo.getType(),
+                nai.networkCapabilities, uid, ignoreBlocked);
     }
 
     /**
@@ -1498,10 +1507,11 @@
     public NetworkInfo getActiveNetworkInfo() {
         enforceAccessPermission();
         final int uid = mDeps.getCallingUid();
-        final NetworkState state = getUnfilteredActiveNetworkState(uid);
-        filterNetworkStateForUid(state, uid, false);
-        maybeLogBlockedNetworkInfo(state.networkInfo, uid);
-        return state.networkInfo;
+        final NetworkAgentInfo nai = getNetworkAgentInfoForUid(uid);
+        if (nai == null) return null;
+        final NetworkInfo networkInfo = getFilteredNetworkInfo(nai, uid, false);
+        maybeLogBlockedNetworkInfo(networkInfo, uid);
+        return networkInfo;
     }
 
     @Override
@@ -1536,30 +1546,37 @@
     @Override
     public NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked) {
         PermissionUtils.enforceNetworkStackPermission(mContext);
-        final NetworkState state = getUnfilteredActiveNetworkState(uid);
-        filterNetworkStateForUid(state, uid, ignoreBlocked);
-        return state.networkInfo;
+        final NetworkAgentInfo nai = getNetworkAgentInfoForUid(uid);
+        if (nai == null) return null;
+        return getFilteredNetworkInfo(nai, uid, ignoreBlocked);
     }
 
-    private NetworkInfo getFilteredNetworkInfo(int networkType, int uid) {
+    /** Returns a NetworkInfo object for a network that doesn't exist. */
+    private NetworkInfo makeFakeNetworkInfo(int networkType, int uid) {
+        final NetworkInfo info = new NetworkInfo(networkType, 0 /* subtype */,
+                getNetworkTypeName(networkType), "" /* subtypeName */);
+        info.setIsAvailable(true);
+        // For compatibility with legacy code, return BLOCKED instead of DISCONNECTED when
+        // background data is restricted.
+        final NetworkCapabilities nc = new NetworkCapabilities();  // Metered.
+        final DetailedState state = isNetworkWithCapabilitiesBlocked(nc, uid, false)
+                ? DetailedState.BLOCKED
+                : DetailedState.DISCONNECTED;
+        info.setDetailedState(getLegacyLockdownState(state),
+                "" /* reason */, null /* extraInfo */);
+        return info;
+    }
+
+    private NetworkInfo getFilteredNetworkInfoForType(int networkType, int uid) {
         if (!mLegacyTypeTracker.isTypeSupported(networkType)) {
             return null;
         }
         final NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
-        final NetworkInfo info;
-        final NetworkCapabilities nc;
-        if (nai != null) {
-            info = new NetworkInfo(nai.networkInfo);
-            info.setType(networkType);
-            nc = nai.networkCapabilities;
-        } else {
-            info = new NetworkInfo(networkType, 0, getNetworkTypeName(networkType), "");
-            info.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
-            info.setIsAvailable(true);
-            nc = new NetworkCapabilities();
+        if (nai == null) {
+            return makeFakeNetworkInfo(networkType, uid);
         }
-        filterNetworkInfo(info, nc, uid, false);
-        return info;
+        return filterNetworkInfo(nai.networkInfo, networkType, nai.networkCapabilities, uid,
+                false);
     }
 
     @Override
@@ -1569,27 +1586,23 @@
         if (getVpnUnderlyingNetworks(uid) != null) {
             // A VPN is active, so we may need to return one of its underlying networks. This
             // information is not available in LegacyTypeTracker, so we have to get it from
-            // getUnfilteredActiveNetworkState.
-            final NetworkState state = getUnfilteredActiveNetworkState(uid);
-            if (state.networkInfo != null && state.networkInfo.getType() == networkType) {
-                filterNetworkStateForUid(state, uid, false);
-                return state.networkInfo;
+            // getNetworkAgentInfoForUid.
+            final NetworkAgentInfo nai = getNetworkAgentInfoForUid(uid);
+            if (nai == null) return null;
+            final NetworkInfo networkInfo = getFilteredNetworkInfo(nai, uid, false);
+            if (networkInfo.getType() == networkType) {
+                return networkInfo;
             }
         }
-        return getFilteredNetworkInfo(networkType, uid);
+        return getFilteredNetworkInfoForType(networkType, uid);
     }
 
     @Override
     public NetworkInfo getNetworkInfoForUid(Network network, int uid, boolean ignoreBlocked) {
         enforceAccessPermission();
         final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
-        if (nai != null) {
-            final NetworkState state = nai.getNetworkState();
-            filterNetworkStateForUid(state, uid, ignoreBlocked);
-            return state.networkInfo;
-        } else {
-            return null;
-        }
+        if (nai == null) return null;
+        return getFilteredNetworkInfo(nai, uid, ignoreBlocked);
     }
 
     @Override
@@ -1617,10 +1630,10 @@
             return null;
         }
         final int uid = mDeps.getCallingUid();
-        if (!isNetworkWithCapabilitiesBlocked(nai.networkCapabilities, uid, false)) {
-            return nai.network;
+        if (isNetworkWithCapabilitiesBlocked(nai.networkCapabilities, uid, false)) {
+            return null;
         }
-        return null;
+        return nai.network;
     }
 
     @Override
@@ -1709,9 +1722,9 @@
     public LinkProperties getActiveLinkProperties() {
         enforceAccessPermission();
         final int uid = mDeps.getCallingUid();
-        NetworkState state = getUnfilteredActiveNetworkState(uid);
-        if (state.linkProperties == null) return null;
-        return linkPropertiesRestrictedForCallerPermissions(state.linkProperties,
+        NetworkAgentInfo nai = getNetworkAgentInfoForUid(uid);
+        if (nai == null) return null;
+        return linkPropertiesRestrictedForCallerPermissions(nai.linkProperties,
                 Binder.getCallingPid(), uid);
     }
 
@@ -2030,25 +2043,24 @@
         return true;
     }
 
-    private class NetdEventCallback extends INetdEventListener.Stub {
+    class DnsResolverUnsolicitedEventCallback extends
+            IDnsResolverUnsolicitedEventListener.Stub {
         @Override
-        public void onPrivateDnsValidationEvent(int netId, String ipAddress,
-                String hostname, boolean validated) {
+        public void onPrivateDnsValidationEvent(final PrivateDnsValidationEventParcel event) {
             try {
                 mHandler.sendMessage(mHandler.obtainMessage(
                         EVENT_PRIVATE_DNS_VALIDATION_UPDATE,
-                        new PrivateDnsValidationUpdate(netId,
-                                InetAddresses.parseNumericAddress(ipAddress),
-                                hostname, validated)));
+                        new PrivateDnsValidationUpdate(event.netId,
+                                InetAddresses.parseNumericAddress(event.ipAddress),
+                                event.hostname, event.validation)));
             } catch (IllegalArgumentException e) {
                 loge("Error parsing ip address in validation event");
             }
         }
 
         @Override
-        public void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs,
-                String hostname,  String[] ipAddresses, int ipAddressesCount, int uid) {
-            NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId);
+        public void onDnsHealthEvent(final DnsHealthEventParcel event) {
+            NetworkAgentInfo nai = getNetworkAgentInfoForNetId(event.netId);
             // Netd event only allow registrants from system. Each NetworkMonitor thread is under
             // the caller thread of registerNetworkAgent. Thus, it's not allowed to register netd
             // event callback for certain nai. e.g. cellular. Register here to pass to
@@ -2057,34 +2069,18 @@
             // callback from each caller type. Need to re-factor NetdEventListenerService to allow
             // multiple NetworkMonitor registrants.
             if (nai != null && nai.satisfies(mDefaultRequest.mRequests.get(0))) {
-                nai.networkMonitor().notifyDnsResponse(returnCode);
+                nai.networkMonitor().notifyDnsResponse(event.healthResult);
             }
         }
 
         @Override
-        public void onNat64PrefixEvent(int netId, boolean added,
-                                       String prefixString, int prefixLength) {
-            mHandler.post(() -> handleNat64PrefixEvent(netId, added, prefixString, prefixLength));
+        public void onNat64PrefixEvent(final Nat64PrefixEventParcel event) {
+            mHandler.post(() -> handleNat64PrefixEvent(event.netId, event.prefixOperation,
+                    event.prefixAddress, event.prefixLength));
         }
 
         @Override
-        public void onConnectEvent(int netId, int error, int latencyMs, String ipAddr, int port,
-                int uid) {
-        }
-
-        @Override
-        public void onWakeupEvent(String prefix, int uid, int ethertype, int ipNextHeader,
-                byte[] dstHw, String srcIp, String dstIp, int srcPort, int dstPort,
-                long timestampNs) {
-        }
-
-        @Override
-        public void onTcpSocketStatsEvent(int[] networkIds, int[] sentPackets, int[] lostPackets,
-                int[] rttsUs, int[] sentAckDiffsMs) {
-        }
-
-        @Override
-        public int getInterfaceVersion() throws RemoteException {
+        public int getInterfaceVersion() {
             return this.VERSION;
         }
 
@@ -2092,16 +2088,17 @@
         public String getInterfaceHash() {
             return this.HASH;
         }
-    };
+    }
 
     @VisibleForTesting
-    protected final INetdEventListener mNetdEventCallback = new NetdEventCallback();
+    protected final DnsResolverUnsolicitedEventCallback mResolverUnsolEventCallback =
+            new DnsResolverUnsolicitedEventCallback();
 
-    private void registerNetdEventCallback() {
+    private void registerDnsResolverUnsolicitedEventListener() {
         try {
-            mDnsResolver.registerEventListener(mNetdEventCallback);
+            mDnsResolver.registerUnsolicitedEventListener(mResolverUnsolEventCallback);
         } catch (Exception e) {
-            loge("Error registering DnsResolver callback: " + e);
+            loge("Error registering DnsResolver unsolicited event callback: " + e);
         }
     }
 
@@ -2191,8 +2188,45 @@
                 "ConnectivityService");
     }
 
+    /**
+     * Performs a strict and comprehensive check of whether a calling package is allowed to
+     * change the state of network, as the condition differs for pre-M, M+, and
+     * privileged/preinstalled apps. The caller is expected to have either the
+     * CHANGE_NETWORK_STATE or the WRITE_SETTINGS permission declared. Either of these
+     * permissions allow changing network state; WRITE_SETTINGS is a runtime permission and
+     * can be revoked, but (except in M, excluding M MRs), CHANGE_NETWORK_STATE is a normal
+     * permission and cannot be revoked. See http://b/23597341
+     *
+     * Note: if the check succeeds because the application holds WRITE_SETTINGS, the operation
+     * of this app will be updated to the current time.
+     */
     private void enforceChangePermission(String callingPkg, String callingAttributionTag) {
-        ConnectivityManager.enforceChangePermission(mContext, callingPkg, callingAttributionTag);
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE)
+                == PackageManager.PERMISSION_GRANTED) {
+            return;
+        }
+
+        if (callingPkg == null) {
+            throw new SecurityException("Calling package name is null.");
+        }
+
+        final AppOpsManager appOpsMgr = mContext.getSystemService(AppOpsManager.class);
+        final int uid = mDeps.getCallingUid();
+        final int mode = appOpsMgr.noteOpNoThrow(AppOpsManager.OPSTR_WRITE_SETTINGS, uid,
+                callingPkg, callingAttributionTag, null /* message */);
+
+        if (mode == AppOpsManager.MODE_ALLOWED) {
+            return;
+        }
+
+        if ((mode == AppOpsManager.MODE_DEFAULT) && (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.WRITE_SETTINGS) == PackageManager.PERMISSION_GRANTED)) {
+            return;
+        }
+
+        throw new SecurityException(callingPkg + " was not granted either of these permissions:"
+                + android.Manifest.permission.CHANGE_NETWORK_STATE + ","
+                + android.Manifest.permission.WRITE_SETTINGS + ".");
     }
 
     private void enforceSettingsPermission() {
@@ -2395,7 +2429,7 @@
         // to ensure the tracking will be initialized correctly.
         mPermissionMonitor.startMonitoring();
         mProxyTracker.loadGlobalProxy();
-        registerNetdEventCallback();
+        registerDnsResolverUnsolicitedEventListener();
 
         synchronized (this) {
             mSystemReady = true;
@@ -3036,9 +3070,6 @@
                 log(nai.toShortString() + " validation " + (valid ? "passed" : "failed") + logMsg);
             }
             if (valid != nai.lastValidated) {
-                if (wasDefault) {
-                    mMetricsLog.logDefaultNetworkValidity(valid);
-                }
                 final int oldScore = nai.getCurrentScore();
                 nai.lastValidated = valid;
                 nai.everValidated |= valid;
@@ -3326,21 +3357,21 @@
         handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties));
     }
 
-    private void handleNat64PrefixEvent(int netId, boolean added, String prefixString,
+    private void handleNat64PrefixEvent(int netId, int operation, String prefixAddress,
             int prefixLength) {
         NetworkAgentInfo nai = mNetworkForNetId.get(netId);
         if (nai == null) return;
 
-        log(String.format("NAT64 prefix %s on netId %d: %s/%d",
-                          (added ? "added" : "removed"), netId, prefixString, prefixLength));
+        log(String.format("NAT64 prefix changed on netId %d: operation=%d, %s/%d",
+                netId, operation, prefixAddress, prefixLength));
 
         IpPrefix prefix = null;
-        if (added) {
+        if (operation == IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_ADDED) {
             try {
-                prefix = new IpPrefix(InetAddresses.parseNumericAddress(prefixString),
+                prefix = new IpPrefix(InetAddresses.parseNumericAddress(prefixAddress),
                         prefixLength);
             } catch (IllegalArgumentException e) {
-                loge("Invalid NAT64 prefix " + prefixString + "/" + prefixLength);
+                loge("Invalid NAT64 prefix " + prefixAddress + "/" + prefixLength);
                 return;
             }
         }
@@ -3459,14 +3490,6 @@
         final boolean wasDefault = isDefaultNetwork(nai);
         if (wasDefault) {
             mDefaultInetConditionPublished = 0;
-            // Log default network disconnection before required book-keeping.
-            // Let rematchAllNetworksAndRequests() below record a new default network event
-            // if there is a fallback. Taken together, the two form a X -> 0, 0 -> Y sequence
-            // whose timestamps tell how long it takes to recover a default network.
-            long now = SystemClock.elapsedRealtime();
-            mMetricsLog.logDefaultNetworkEvent(null, 0, false,
-                    null /* lp */, null /* nc */, nai.network, nai.getCurrentScore(),
-                    nai.linkProperties, nai.networkCapabilities);
         }
         notifyIfacesChangedForNetworkStats();
         // TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
@@ -6020,7 +6043,7 @@
         final NetworkAgentInfo nai = new NetworkAgentInfo(na,
                 new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
                 currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
-                this, mNetd, mDnsResolver, mNMS, providerId, uid, mQosCallbackTracker);
+                this, mNetd, mDnsResolver, providerId, uid, mQosCallbackTracker);
 
         // Make sure the LinkProperties and NetworkCapabilities reflect what the agent info says.
         processCapabilitiesFromAgent(nai, nc);
@@ -7102,27 +7125,6 @@
         updateTcpBufferSizes(null != newDefaultNetwork
                 ? newDefaultNetwork.linkProperties.getTcpBufferSizes() : null);
         notifyIfacesChangedForNetworkStats();
-
-        // Log 0 -> X and Y -> X default network transitions, where X is the new default.
-        final Network network = (newDefaultNetwork != null) ? newDefaultNetwork.network : null;
-        final int score = (newDefaultNetwork != null) ? newDefaultNetwork.getCurrentScore() : 0;
-        final boolean validated = newDefaultNetwork != null && newDefaultNetwork.lastValidated;
-        final LinkProperties lp = (newDefaultNetwork != null)
-                ? newDefaultNetwork.linkProperties : null;
-        final NetworkCapabilities nc = (newDefaultNetwork != null)
-                ? newDefaultNetwork.networkCapabilities : null;
-
-        final Network prevNetwork = (oldDefaultNetwork != null)
-                ? oldDefaultNetwork.network : null;
-        final int prevScore = (oldDefaultNetwork != null)
-                ? oldDefaultNetwork.getCurrentScore() : 0;
-        final LinkProperties prevLp = (oldDefaultNetwork != null)
-                ? oldDefaultNetwork.linkProperties : null;
-        final NetworkCapabilities prevNc = (oldDefaultNetwork != null)
-                ? oldDefaultNetwork.networkCapabilities : null;
-
-        mMetricsLog.logDefaultNetworkEvent(network, score, validated, lp, nc,
-                prevNetwork, prevScore, prevLp, prevNc);
     }
 
     private void makeDefaultForApps(@NonNull final NetworkRequestInfo nri,
@@ -7942,8 +7944,16 @@
 
         final UnderlyingNetworkInfo[] underlyingNetworkInfos = getAllVpnInfo();
         try {
-            mStatsService.forceUpdateIfaces(getDefaultNetworks(), getAllNetworkState(), activeIface,
-                    underlyingNetworkInfos);
+            final ArrayList<NetworkStateSnapshot> snapshots = new ArrayList<>();
+            // TODO: Directly use NetworkStateSnapshot when feasible.
+            for (final NetworkState state : getAllNetworkState()) {
+                final NetworkStateSnapshot snapshot = new NetworkStateSnapshot(state.network,
+                        state.networkCapabilities, state.linkProperties, state.subscriberId,
+                        state.legacyNetworkType);
+                snapshots.add(snapshot);
+            }
+            mStatsService.forceUpdateIfaces(getDefaultNetworks(), snapshots.toArray(
+                    new NetworkStateSnapshot[0]), activeIface, underlyingNetworkInfos);
         } catch (Exception ignored) {
         }
     }
@@ -8176,7 +8186,7 @@
             TestNetworkService.enforceTestNetworkPermissions(mContext);
 
             if (mTNS == null) {
-                mTNS = new TestNetworkService(mContext, mNMS);
+                mTNS = new TestNetworkService(mContext);
             }
 
             return mTNS;
@@ -8649,6 +8659,28 @@
         notifyDataStallSuspected(p, network.getNetId());
     }
 
+    private class NetdCallback extends BaseNetdUnsolicitedEventListener {
+        @Override
+        public void onInterfaceClassActivityChanged(boolean isActive, int transportType,
+                long timestampNs, int uid) {
+            mNetworkActivityTracker.setAndReportNetworkActive(isActive, transportType, timestampNs);
+        }
+
+        @Override
+        public void onInterfaceLinkStateChanged(String iface, boolean up) {
+            for (NetworkAgentInfo nai : mNetworkAgentInfos) {
+                nai.clatd.interfaceLinkStateChanged(iface, up);
+            }
+        }
+
+        @Override
+        public void onInterfaceRemoved(String iface) {
+            for (NetworkAgentInfo nai : mNetworkAgentInfos) {
+                nai.clatd.interfaceRemoved(iface);
+            }
+        }
+    }
+
     private final LegacyNetworkActivityTracker mNetworkActivityTracker;
 
     /**
@@ -8659,7 +8691,6 @@
         private static final int NO_UID = -1;
         private final Context mContext;
         private final INetd mNetd;
-        private final INetworkManagementService mNMS;
         private final RemoteCallbackList<INetworkActivityListener> mNetworkActivityListeners =
                 new RemoteCallbackList<>();
         // Indicate the current system default network activity is active or not.
@@ -8680,43 +8711,29 @@
         }
 
         LegacyNetworkActivityTracker(@NonNull Context context, @NonNull Handler handler,
-                @NonNull INetworkManagementService nms, @NonNull INetd netd) {
+                @NonNull INetd netd) {
             mContext = context;
-            mNMS = nms;
             mNetd = netd;
             mHandler = handler;
-            try {
-                mNMS.registerObserver(mDataActivityObserver);
-            } catch (RemoteException e) {
-                loge("Error registering observer :" + e);
-            }
         }
 
-        // TODO: Migrate away the dependency with INetworkManagementEventObserver.
-        private final INetworkManagementEventObserver mDataActivityObserver =
-                new BaseNetworkObserver() {
-                    @Override
-                    public void interfaceClassDataActivityChanged(int transportType, boolean active,
-                            long tsNanos, int uid) {
-                        sendDataActivityBroadcast(transportTypeToLegacyType(transportType), active,
-                                tsNanos);
-                        synchronized (mActiveIdleTimers) {
-                            mNetworkActive = active;
-                            // If there are no idle timers, it means that system is not monitoring
-                            // activity, so the system default network for those default network
-                            // unspecified apps is always considered active.
-                            //
-                            // TODO: If the mActiveIdleTimers is empty, netd will actually not send
-                            // any network activity change event. Whenever this event is received,
-                            // the mActiveIdleTimers should be always not empty. The legacy behavior
-                            // is no-op. Remove to refer to mNetworkActive only.
-                            if (mNetworkActive || mActiveIdleTimers.isEmpty()) {
-                                mHandler.sendMessage(
-                                        mHandler.obtainMessage(EVENT_REPORT_NETWORK_ACTIVITY));
-                            }
-                        }
-                    }
-                };
+        public void setAndReportNetworkActive(boolean active, int transportType, long tsNanos) {
+            sendDataActivityBroadcast(transportTypeToLegacyType(transportType), active, tsNanos);
+            synchronized (mActiveIdleTimers) {
+                mNetworkActive = active;
+                // If there are no idle timers, it means that system is not monitoring
+                // activity, so the system default network for those default network
+                // unspecified apps is always considered active.
+                //
+                // TODO: If the mActiveIdleTimers is empty, netd will actually not send
+                // any network activity change event. Whenever this event is received,
+                // the mActiveIdleTimers should be always not empty. The legacy behavior
+                // is no-op. Remove to refer to mNetworkActive only.
+                if (mNetworkActive || mActiveIdleTimers.isEmpty()) {
+                    mHandler.sendMessage(mHandler.obtainMessage(EVENT_REPORT_NETWORK_ACTIVITY));
+                }
+            }
+        }
 
         // The network activity should only be updated from ConnectivityService handler thread
         // when mActiveIdleTimers lock is held.
diff --git a/services/core/java/com/android/server/ConnectivityServiceInitializer.java b/services/core/java/com/android/server/ConnectivityServiceInitializer.java
index 0779f71..097441f 100644
--- a/services/core/java/com/android/server/ConnectivityServiceInitializer.java
+++ b/services/core/java/com/android/server/ConnectivityServiceInitializer.java
@@ -21,7 +21,6 @@
 
 import android.content.Context;
 import android.net.INetworkStatsService;
-import android.os.INetworkManagementService;
 import android.os.ServiceManager;
 import android.util.Log;
 
@@ -38,8 +37,7 @@
         // Load JNI libraries used by ConnectivityService and its dependencies
         System.loadLibrary("service-connectivity");
         // TODO: Define formal APIs to get the needed services.
-        mConnectivity = new ConnectivityService(context, getNetworkManagementService(),
-                getNetworkStatsService());
+        mConnectivity = new ConnectivityService(context, getNetworkStatsService());
     }
 
     @Override
@@ -49,11 +47,6 @@
                 /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
     }
 
-    private INetworkManagementService getNetworkManagementService() {
-        return INetworkManagementService.Stub.asInterface(
-               ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
-    }
-
     private INetworkStatsService getNetworkStatsService() {
         return INetworkStatsService.Stub.asInterface(
                 ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 4405408..10d6570 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -44,7 +44,6 @@
 import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.content.Context;
-import android.net.ConnectivityManager;
 import android.net.INetd;
 import android.net.INetdUnsolicitedEventListener;
 import android.net.INetworkManagementEventObserver;
@@ -54,7 +53,6 @@
 import android.net.InterfaceConfigurationParcel;
 import android.net.IpPrefix;
 import android.net.LinkAddress;
-import android.net.Network;
 import android.net.NetworkPolicyManager;
 import android.net.NetworkStack;
 import android.net.NetworkStats;
@@ -974,19 +972,6 @@
     }
 
     @Override
-    public void setDnsForwarders(Network network, String[] dns) {
-        NetworkStack.checkNetworkStackPermission(mContext);
-
-        int netId = (network != null) ? network.netId : ConnectivityManager.NETID_UNSET;
-
-        try {
-            mNetdService.tetherDnsSet(netId, dns);
-        } catch (RemoteException | ServiceSpecificException e) {
-            throw new IllegalStateException(e);
-        }
-    }
-
-    @Override
     public String[] getDnsForwarders() {
         NetworkStack.checkNetworkStackPermission(mContext);
         try {
@@ -1775,27 +1760,6 @@
     }
 
     @Override
-    public void addLegacyRouteForNetId(int netId, RouteInfo routeInfo, int uid) {
-        NetworkStack.checkNetworkStackPermission(mContext);
-
-        final LinkAddress la = routeInfo.getDestinationLinkAddress();
-        final String ifName = routeInfo.getInterface();
-        final String dst = la.toString();
-        final String nextHop;
-
-        if (routeInfo.hasGateway()) {
-            nextHop = routeInfo.getGateway().getHostAddress();
-        } else {
-            nextHop = "";
-        }
-        try {
-            mNetdService.networkAddLegacyRoute(netId, ifName, dst, nextHop, uid);
-        } catch (RemoteException | ServiceSpecificException e) {
-            throw new IllegalStateException(e);
-        }
-    }
-
-    @Override
     public void allowProtect(int uid) {
         NetworkStack.checkNetworkStackPermission(mContext);
 
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index 84e429d..f2782f6 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -25,9 +25,9 @@
 import static android.content.Intent.EXTRA_PACKAGE_NAME;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.hardware.SensorPrivacyManager.EXTRA_SENSOR;
+import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
+import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE;
 import static android.os.UserHandle.USER_SYSTEM;
-import static android.service.SensorPrivacyIndividualEnabledSensorProto.CAMERA;
-import static android.service.SensorPrivacyIndividualEnabledSensorProto.MICROPHONE;
 import static android.service.SensorPrivacyIndividualEnabledSensorProto.UNKNOWN;
 
 import android.annotation.NonNull;
@@ -406,12 +406,12 @@
          */
         @Override
         public void setSensorPrivacy(boolean enable) {
+            enforceManageSensorPrivacyPermission();
             // Keep the state consistent between all users to make it a single global state
             forAllUsers(userId -> setSensorPrivacy(userId, enable));
         }
 
         private void setSensorPrivacy(@UserIdInt int userId, boolean enable) {
-            enforceSensorPrivacyPermission();
             synchronized (mLock) {
                 mEnabled.put(userId, enable);
                 persistSensorPrivacyStateLocked();
@@ -421,7 +421,7 @@
 
         @Override
         public void setIndividualSensorPrivacy(@UserIdInt int userId, int sensor, boolean enable) {
-            enforceSensorPrivacyPermission();
+            enforceManageSensorPrivacyPermission();
             synchronized (mLock) {
                 SparseBooleanArray userIndividualEnabled = mIndividualEnabled.get(userId,
                         new SparseBooleanArray());
@@ -448,6 +448,7 @@
         @Override
         public void setIndividualSensorPrivacyForProfileGroup(@UserIdInt int userId, int sensor,
                 boolean enable) {
+            enforceManageSensorPrivacyPermission();
             int parentId = mUserManagerInternal.getProfileParentId(userId);
             forAllUsers(userId2 -> {
                 if (parentId == mUserManagerInternal.getProfileParentId(userId2)) {
@@ -460,21 +461,35 @@
          * Enforces the caller contains the necessary permission to change the state of sensor
          * privacy.
          */
-        private void enforceSensorPrivacyPermission() {
-            if (mContext.checkCallingOrSelfPermission(
-                    MANAGE_SENSOR_PRIVACY) == PERMISSION_GRANTED) {
-                return;
-            }
-            throw new SecurityException(
+        private void enforceManageSensorPrivacyPermission() {
+            enforcePermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY,
                     "Changing sensor privacy requires the following permission: "
                             + MANAGE_SENSOR_PRIVACY);
         }
 
         /**
+         * Enforces the caller contains the necessary permission to observe changes to the sate of
+         * sensor privacy.
+         */
+        private void enforceObserveSensorPrivacyPermission() {
+            enforcePermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY,
+                    "Observing sensor privacy changes requires the following permission: "
+                            + android.Manifest.permission.OBSERVE_SENSOR_PRIVACY);
+        }
+
+        private void enforcePermission(String permission, String message) {
+            if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
+                return;
+            }
+            throw new SecurityException(message);
+        }
+
+        /**
          * Returns whether sensor privacy is enabled.
          */
         @Override
         public boolean isSensorPrivacyEnabled() {
+            enforceObserveSensorPrivacyPermission();
             return isSensorPrivacyEnabled(USER_SYSTEM);
         }
 
@@ -486,6 +501,7 @@
 
         @Override
         public boolean isIndividualSensorPrivacyEnabled(@UserIdInt int userId, int sensor) {
+            enforceObserveSensorPrivacyPermission();
             synchronized (mLock) {
                 SparseBooleanArray states = mIndividualEnabled.get(userId);
                 if (states == null) {
@@ -703,6 +719,7 @@
          */
         @Override
         public void addSensorPrivacyListener(ISensorPrivacyListener listener) {
+            enforceObserveSensorPrivacyPermission();
             if (listener == null) {
                 throw new NullPointerException("listener cannot be null");
             }
@@ -715,6 +732,7 @@
         @Override
         public void addIndividualSensorPrivacyListener(int userId, int sensor,
                 ISensorPrivacyListener listener) {
+            enforceObserveSensorPrivacyPermission();
             if (listener == null) {
                 throw new NullPointerException("listener cannot be null");
             }
@@ -726,6 +744,7 @@
          */
         @Override
         public void removeSensorPrivacyListener(ISensorPrivacyListener listener) {
+            enforceObserveSensorPrivacyPermission();
             if (listener == null) {
                 throw new NullPointerException("listener cannot be null");
             }
@@ -735,6 +754,7 @@
         @Override
         public void suppressIndividualSensorPrivacyReminders(int userId, String packageName,
                 IBinder token, boolean suppress) {
+            enforceManageSensorPrivacyPermission();
             Objects.requireNonNull(packageName);
             Objects.requireNonNull(token);
 
@@ -886,13 +906,13 @@
         }
 
         /**
-         * Convert a string into a {@link SensorPrivacyManager.IndividualSensor id}.
+         * Convert a string into a {@link SensorPrivacyManager.Sensors.Sensor id}.
          *
          * @param sensor The name to convert
          *
          * @return The id corresponding to the name
          */
-        private @SensorPrivacyManager.IndividualSensor int sensorStrToId(@Nullable String sensor) {
+        private @SensorPrivacyManager.Sensors.Sensor int sensorStrToId(@Nullable String sensor) {
             if (sensor == null) {
                 return UNKNOWN;
             }
@@ -950,7 +970,7 @@
                                 return -1;
                             }
 
-                            enforceSensorPrivacyPermission();
+                            enforceManageSensorPrivacyPermission();
 
                             synchronized (mLock) {
                                 SparseBooleanArray individualEnabled =
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 2f98199..c5233f4 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -24,6 +24,10 @@
 import static android.app.AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE;
 import static android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES;
 import static android.app.AppOpsManager.OP_WRITE_EXTERNAL_STORAGE;
+import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
+import static android.app.PendingIntent.FLAG_IMMUTABLE;
+import static android.app.PendingIntent.FLAG_ONE_SHOT;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.pm.PackageManager.MATCH_ANY_USER;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
@@ -51,9 +55,11 @@
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
+import android.app.AnrController;
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
 import android.app.KeyguardManager;
+import android.app.PendingIntent;
 import android.app.admin.SecurityLog;
 import android.app.usage.StorageStatsManager;
 import android.content.BroadcastReceiver;
@@ -938,14 +944,29 @@
 
         if (transcodeEnabled) {
             LocalServices.getService(ActivityManagerInternal.class)
-                    .registerAnrController((packageName, uid) -> {
-                        try {
-                            return mStorageSessionController.getAnrDelayMillis(packageName, uid);
-                        } catch (ExternalStorageServiceException e) {
-                            Log.e(TAG, "Failed to get ANR delay for " + packageName, e);
-                            return 0;
-                        }
-                    });
+                .registerAnrController(new ExternalStorageServiceAnrController());
+        }
+    }
+
+    // TODO(b/170486601): Check transcoding status based on events pushed from the MediaProvider
+    private class ExternalStorageServiceAnrController implements AnrController {
+        @Override
+        public long getAnrDelayMillis(String packageName, int uid) {
+            int delay = SystemProperties.getInt("sys.fuse.transcode_anr_delay", 0);
+            Log.d(TAG, "getAnrDelayMillis: " + packageName + ". Delaying for " + delay + "ms");
+            return delay;
+        }
+
+        @Override
+        public void onAnrDelayStarted(String packageName, int uid) {
+            Log.d(TAG, "onAnrDelayStarted: " + packageName);
+        }
+
+        @Override
+        public boolean onAnrDelayCompleted(String packageName, int uid) {
+            boolean show = SystemProperties.getBoolean("sys.fuse.transcode_anr_dialog_show", true);
+            Log.d(TAG, "onAnrDelayCompleted: " + packageName + ". Show: " + show);
+            return show;
         }
     }
 
@@ -3322,6 +3343,87 @@
         }
     }
 
+    @Override
+    public void notifyAppIoBlocked(String volumeUuid, int uid, int tid, int reason) {
+        enforceExternalStorageService();
+
+        mStorageSessionController.notifyAppIoBlocked(volumeUuid, uid, tid, reason);
+    }
+
+    @Override
+    public void notifyAppIoResumed(String volumeUuid, int uid, int tid, int reason) {
+        enforceExternalStorageService();
+
+        mStorageSessionController.notifyAppIoResumed(volumeUuid, uid, tid, reason);
+    }
+
+    private boolean isAppIoBlocked(int uid) {
+        return mStorageSessionController.isAppIoBlocked(uid);
+    }
+
+    /**
+     * Enforces that the caller is the {@link ExternalStorageService}
+     *
+     * @throws SecurityException if the caller doesn't have the
+     * {@link android.Manifest.permission.WRITE_MEDIA_STORAGE} permission or is not the
+     * {@link ExternalStorageService}
+     */
+    private void enforceExternalStorageService() {
+        enforcePermission(android.Manifest.permission.WRITE_MEDIA_STORAGE);
+        int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
+        if (callingAppId != mMediaStoreAuthorityAppId) {
+            throw new SecurityException("Only the ExternalStorageService is permitted");
+        }
+    }
+
+    /**
+     * Returns PendingIntent which can be used by Apps with MANAGE_EXTERNAL_STORAGE permission
+     * to launch the manageSpaceActivity of the App specified by packageName.
+     */
+    @Override
+    @Nullable
+    public PendingIntent getManageSpaceActivityIntent(
+            @NonNull String packageName, int requestCode) {
+        // Only Apps with MANAGE_EXTERNAL_STORAGE permission should be able to call this API.
+        enforcePermission(android.Manifest.permission.MANAGE_EXTERNAL_STORAGE);
+
+        // We want to call the manageSpaceActivity as a SystemService and clear identity
+        // of the calling App
+        int originalUid = Binder.getCallingUidOrThrow();
+        long token = Binder.clearCallingIdentity();
+
+        try {
+            ApplicationInfo appInfo = mIPackageManager.getApplicationInfo(packageName, 0,
+                    UserHandle.getUserId(originalUid));
+            if (appInfo == null) {
+                throw new IllegalArgumentException(
+                        "Invalid packageName");
+            }
+            if (appInfo.manageSpaceActivityName == null) {
+                Log.i(TAG, packageName + " doesn't have a manageSpaceActivity");
+                return null;
+            }
+            Context targetAppContext = mContext.createPackageContext(packageName, 0);
+
+            Intent intent = new Intent(Intent.ACTION_DEFAULT);
+            intent.setClassName(packageName,
+                    appInfo.manageSpaceActivityName);
+            intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
+
+            PendingIntent activity = PendingIntent.getActivity(targetAppContext, requestCode,
+                    intent,
+                    FLAG_ONE_SHOT | FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE);
+            return activity;
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new IllegalArgumentException(
+                    "packageName not found");
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     /** Not thread safe */
     class AppFuseMountScope extends AppFuseBridge.MountScope {
         private boolean mMounted = false;
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index b09b6ca..5a5f1a3 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -313,9 +313,9 @@
 
     private List<PhysicalChannelConfig> mPhysicalChannelConfigs;
 
-    private boolean mIsDataEnabled = false;
+    private boolean[] mIsDataEnabled;
 
-    private int mDataEnabledReason;
+    private int[] mDataEnabledReason;
 
     private Map<Integer, Long> mAllowedNetworkTypesList;
 
@@ -524,6 +524,8 @@
         mOutgoingCallEmergencyNumber = copyOf(mOutgoingCallEmergencyNumber, mNumPhones);
         mOutgoingSmsEmergencyNumber = copyOf(mOutgoingSmsEmergencyNumber, mNumPhones);
         mTelephonyDisplayInfos = copyOf(mTelephonyDisplayInfos, mNumPhones);
+        mIsDataEnabled= copyOf(mIsDataEnabled, mNumPhones);
+        mDataEnabledReason = copyOf(mDataEnabledReason, mNumPhones);
 
         // ds -> ss switch.
         if (mNumPhones < oldNumPhones) {
@@ -565,6 +567,8 @@
             mPreciseDataConnectionStates.add(new ArrayMap<>());
             mBarringInfo.add(i, new BarringInfo());
             mTelephonyDisplayInfos[i] = null;
+            mIsDataEnabled[i] = false;
+            mDataEnabledReason[i] = TelephonyManager.DATA_ENABLED_REASON_USER;
             mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build());
         }
     }
@@ -626,6 +630,8 @@
         mTelephonyDisplayInfos = new TelephonyDisplayInfo[numPhones];
         mPhysicalChannelConfigs = new ArrayList<>();
         mAllowedNetworkTypesList = new HashMap<>();
+        mIsDataEnabled = new boolean[numPhones];
+        mDataEnabledReason = new int[numPhones];
         for (int i = 0; i < numPhones; i++) {
             mCallState[i] =  TelephonyManager.CALL_STATE_IDLE;
             mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
@@ -655,6 +661,8 @@
             mPreciseDataConnectionStates.add(new ArrayMap<>());
             mBarringInfo.add(i, new BarringInfo());
             mTelephonyDisplayInfos[i] = null;
+            mIsDataEnabled[i] = false;
+            mDataEnabledReason[i] = TelephonyManager.DATA_ENABLED_REASON_USER;
             mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build());
         }
 
@@ -1150,7 +1158,8 @@
                 if (events.contains(
                         PhoneStateListener.EVENT_DATA_ENABLED_CHANGED)) {
                     try {
-                        r.callback.onDataEnabledChanged(mIsDataEnabled, mDataEnabledReason);
+                        r.callback.onDataEnabledChanged(
+                                mIsDataEnabled[phoneId], mDataEnabledReason[phoneId]);
                     } catch (RemoteException ex) {
                         remove(r.binder);
                     }
@@ -2370,30 +2379,36 @@
     /**
      * Notify that the data enabled has changed.
      *
+     * @param phoneId the phone id.
+     * @param subId the subId.
      * @param enabled True if data is enabled, otherwise disabled.
      * @param reason  Reason for data enabled/disabled. See {@code DATA_*} in
      *                {@link TelephonyManager}.
      */
-    public void notifyDataEnabled(boolean enabled,
+    public void notifyDataEnabled(int phoneId, int subId, boolean enabled,
                                   @TelephonyManager.DataEnabledReason int reason) {
         if (!checkNotifyPermission("notifyDataEnabled()")) {
             return;
         }
 
         if (VDBG) {
-            log("notifyDataEnabled: enabled=" + enabled + " reason=" + reason);
+            log("notifyDataEnabled: PhoneId=" + phoneId + " subId=" + subId +
+                    " enabled=" + enabled + " reason=" + reason);
         }
 
-        mIsDataEnabled = enabled;
-        mDataEnabledReason = reason;
         synchronized (mRecords) {
-            for (Record r : mRecords) {
-                if (r.matchPhoneStateListenerEvent(
-                        PhoneStateListener.EVENT_DATA_ENABLED_CHANGED)) {
-                    try {
-                        r.callback.onDataEnabledChanged(enabled, reason);
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
+            if (validatePhoneId(phoneId)) {
+                mIsDataEnabled[phoneId] = enabled;
+                mDataEnabledReason[phoneId] = reason;
+                for (Record r : mRecords) {
+                    if (r.matchPhoneStateListenerEvent(
+                            PhoneStateListener.EVENT_DATA_ENABLED_CHANGED)
+                            && idMatch(r.subId, subId, phoneId)) {
+                        try {
+                            r.callback.onDataEnabledChanged(enabled, reason);
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
                     }
                 }
             }
@@ -2481,6 +2496,8 @@
                 pw.println("mOutgoingSmsEmergencyNumber=" + mOutgoingSmsEmergencyNumber[i]);
                 pw.println("mBarringInfo=" + mBarringInfo.get(i));
                 pw.println("mTelephonyDisplayInfo=" + mTelephonyDisplayInfos[i]);
+                pw.println("mIsDataEnabled=" + mIsDataEnabled);
+                pw.println("mDataEnabledReason=" + mDataEnabledReason);
                 pw.decreaseIndent();
             }
             pw.println("mCarrierNetworkChangeState=" + mCarrierNetworkChangeState);
@@ -2491,8 +2508,6 @@
             pw.println("mDefaultPhoneId=" + mDefaultPhoneId);
             pw.println("mDefaultSubId=" + mDefaultSubId);
             pw.println("mPhysicalChannelConfigs=" + mPhysicalChannelConfigs);
-            pw.println("mIsDataEnabled=" + mIsDataEnabled);
-            pw.println("mDataEnabledReason=" + mDataEnabledReason);
 
             pw.decreaseIndent();
 
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index 96f832d..55408ea 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -32,7 +32,6 @@
 import android.net.NetworkAgentConfig;
 import android.net.NetworkCapabilities;
 import android.net.NetworkProvider;
-import android.net.NetworkStack;
 import android.net.RouteInfo;
 import android.net.StringNetworkSpecifier;
 import android.net.TestNetworkInterface;
@@ -41,7 +40,6 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
-import android.os.INetworkManagementService;
 import android.os.Looper;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -51,6 +49,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.net.module.util.NetdUtils;
 import com.android.net.module.util.NetworkStackConstants;
+import com.android.net.module.util.PermissionUtils;
 
 import java.io.UncheckedIOException;
 import java.net.Inet4Address;
@@ -69,7 +68,6 @@
     @NonNull private static final AtomicInteger sTestTunIndex = new AtomicInteger();
 
     @NonNull private final Context mContext;
-    @NonNull private final INetworkManagementService mNMS;
     @NonNull private final INetd mNetd;
 
     @NonNull private final HandlerThread mHandlerThread;
@@ -82,14 +80,12 @@
     private static native int jniCreateTunTap(boolean isTun, @NonNull String iface);
 
     @VisibleForTesting
-    protected TestNetworkService(
-            @NonNull Context context, @NonNull INetworkManagementService netManager) {
+    protected TestNetworkService(@NonNull Context context) {
         mHandlerThread = new HandlerThread("TestNetworkServiceThread");
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper());
 
         mContext = Objects.requireNonNull(context, "missing Context");
-        mNMS = Objects.requireNonNull(netManager, "missing INetworkManagementService");
         mNetd = Objects.requireNonNull(NetdService.getInstance(), "could not get netd instance");
         mCm = mContext.getSystemService(ConnectivityManager.class);
         mNetworkProvider = new NetworkProvider(mContext, mHandler.getLooper(),
@@ -324,7 +320,7 @@
         try {
             final long token = Binder.clearCallingIdentity();
             try {
-                NetworkStack.checkNetworkStackPermission(mContext);
+                PermissionUtils.enforceNetworkStackPermission(mContext);
                 NetdUtils.setInterfaceUp(mNetd, iface);
             } finally {
                 Binder.restoreCallingIdentity(token);
diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java
index 5d89bf1..56aabc20 100644
--- a/services/core/java/com/android/server/VpnManagerService.java
+++ b/services/core/java/com/android/server/VpnManagerService.java
@@ -47,7 +47,6 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.security.Credentials;
-import android.security.KeyStore;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseArray;
@@ -60,6 +59,7 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.connectivity.Vpn;
+import com.android.server.connectivity.VpnProfileStore;
 import com.android.server.net.LockdownVpnTracker;
 
 import java.io.FileDescriptor;
@@ -83,7 +83,7 @@
     private final Dependencies mDeps;
 
     private final ConnectivityManager mCm;
-    private final KeyStore mKeyStore;
+    private final VpnProfileStore mVpnProfileStore;
     private final INetworkManagementService mNMS;
     private final INetd mNetd;
     private final UserManager mUserManager;
@@ -114,9 +114,9 @@
             return new HandlerThread("VpnManagerService");
         }
 
-        /** Returns the KeyStore instance to be used by this class. */
-        public KeyStore getKeyStore() {
-            return KeyStore.getInstance();
+        /** Return the VpnProfileStore to be used by this class */
+        public VpnProfileStore getVpnProfileStore() {
+            return new VpnProfileStore();
         }
 
         public INetd getNetd() {
@@ -135,7 +135,7 @@
         mHandlerThread = mDeps.makeHandlerThread();
         mHandlerThread.start();
         mHandler = mHandlerThread.getThreadHandler();
-        mKeyStore = mDeps.getKeyStore();
+        mVpnProfileStore = mDeps.getVpnProfileStore();
         mUserAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
         mCm = mContext.getSystemService(ConnectivityManager.class);
         mNMS = mDeps.getINetworkManagementService();
@@ -289,7 +289,7 @@
     public boolean provisionVpnProfile(@NonNull VpnProfile profile, @NonNull String packageName) {
         final int user = UserHandle.getUserId(mDeps.getCallingUid());
         synchronized (mVpns) {
-            return mVpns.get(user).provisionVpnProfile(packageName, profile, mKeyStore);
+            return mVpns.get(user).provisionVpnProfile(packageName, profile);
         }
     }
 
@@ -307,7 +307,7 @@
     public void deleteVpnProfile(@NonNull String packageName) {
         final int user = UserHandle.getUserId(mDeps.getCallingUid());
         synchronized (mVpns) {
-            mVpns.get(user).deleteVpnProfile(packageName, mKeyStore);
+            mVpns.get(user).deleteVpnProfile(packageName);
         }
     }
 
@@ -325,7 +325,7 @@
         final int user = UserHandle.getUserId(mDeps.getCallingUid());
         synchronized (mVpns) {
             throwIfLockdownEnabled();
-            mVpns.get(user).startVpnProfile(packageName, mKeyStore);
+            mVpns.get(user).startVpnProfile(packageName);
         }
     }
 
@@ -358,7 +358,7 @@
         }
         synchronized (mVpns) {
             throwIfLockdownEnabled();
-            mVpns.get(user).startLegacyVpn(profile, mKeyStore, null /* underlying */, egress);
+            mVpns.get(user).startLegacyVpn(profile, null /* underlying */, egress);
         }
     }
 
@@ -396,7 +396,7 @@
     }
 
     private boolean isLockdownVpnEnabled() {
-        return mKeyStore.contains(Credentials.LOCKDOWN_VPN);
+        return mVpnProfileStore.get(Credentials.LOCKDOWN_VPN) != null;
     }
 
     @Override
@@ -417,14 +417,14 @@
                 return true;
             }
 
-            byte[] profileTag = mKeyStore.get(Credentials.LOCKDOWN_VPN);
+            byte[] profileTag = mVpnProfileStore.get(Credentials.LOCKDOWN_VPN);
             if (profileTag == null) {
                 loge("Lockdown VPN configured but cannot be read from keystore");
                 return false;
             }
             String profileName = new String(profileTag);
             final VpnProfile profile = VpnProfile.decode(
-                    profileName, mKeyStore.get(Credentials.VPN + profileName));
+                    profileName, mVpnProfileStore.get(Credentials.VPN + profileName));
             if (profile == null) {
                 loge("Lockdown VPN configured invalid profile " + profileName);
                 setLockdownTracker(null);
@@ -437,7 +437,7 @@
                 return false;
             }
             setLockdownTracker(
-                    new LockdownVpnTracker(mContext, mHandler, mKeyStore, vpn,  profile));
+                    new LockdownVpnTracker(mContext, mHandler, vpn,  profile));
         }
 
         return true;
@@ -495,7 +495,7 @@
                 return false;
             }
 
-            return vpn.startAlwaysOnVpn(mKeyStore);
+            return vpn.startAlwaysOnVpn();
         }
     }
 
@@ -510,7 +510,7 @@
                 logw("User " + userId + " has no Vpn configuration");
                 return false;
             }
-            return vpn.isAlwaysOnPackageSupported(packageName, mKeyStore);
+            return vpn.isAlwaysOnPackageSupported(packageName);
         }
     }
 
@@ -531,11 +531,11 @@
                 logw("User " + userId + " has no Vpn configuration");
                 return false;
             }
-            if (!vpn.setAlwaysOnPackage(packageName, lockdown, lockdownAllowlist, mKeyStore)) {
+            if (!vpn.setAlwaysOnPackage(packageName, lockdown, lockdownAllowlist)) {
                 return false;
             }
             if (!startAlwaysOnVpn(userId)) {
-                vpn.setAlwaysOnPackage(null, false, null, mKeyStore);
+                vpn.setAlwaysOnPackage(null, false, null);
                 return false;
             }
         }
@@ -705,7 +705,8 @@
                 loge("Starting user already has a VPN");
                 return;
             }
-            userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId, mKeyStore);
+            userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId,
+                    new VpnProfileStore());
             mVpns.put(userId, userVpn);
             if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
                 updateLockdownVpn();
@@ -777,7 +778,7 @@
             if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName)) {
                 log("Restarting always-on VPN package " + packageName + " for user "
                         + userId);
-                vpn.startAlwaysOnVpn(mKeyStore);
+                vpn.startAlwaysOnVpn();
             }
         }
     }
@@ -798,7 +799,7 @@
             if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName) && !isReplacing) {
                 log("Removing always-on VPN package " + packageName + " for user "
                         + userId);
-                vpn.setAlwaysOnPackage(null, false, null, mKeyStore);
+                vpn.setAlwaysOnPackage(null, false, null);
             }
         }
     }
@@ -843,7 +844,7 @@
             if (mLockdownEnabled && userId == UserHandle.USER_SYSTEM) {
                 final long ident = Binder.clearCallingIdentity();
                 try {
-                    mKeyStore.delete(Credentials.LOCKDOWN_VPN);
+                    mVpnProfileStore.remove(Credentials.LOCKDOWN_VPN);
                     mLockdownEnabled = false;
                     setLockdownTracker(null);
                 } finally {
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 9930eac..7375523 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -279,7 +279,7 @@
         mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
         mHandler = new MessageHandler(injector.getMessageHandlerLooper());
         mAuthenticatorCache = mInjector.getAccountAuthenticatorCache();
-        mAuthenticatorCache.setListener(this, null /* Handler */);
+        mAuthenticatorCache.setListener(this, mHandler);
 
         sThis.set(this);
 
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 2efc83c..d998ebb 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -20,10 +20,35 @@
 import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND;
 import static android.Manifest.permission.SYSTEM_ALERT_WINDOW;
 import static android.app.ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
+import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT;
 import static android.app.ActivityManager.PROCESS_STATE_RECEIVER;
 import static android.app.ActivityManager.PROCESS_STATE_TOP;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST;
+import static android.os.PowerWhitelistManager.REASON_ACTIVITY_STARTER;
+import static android.os.PowerWhitelistManager.REASON_ALLOWLISTED_PACKAGE;
+import static android.os.PowerWhitelistManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
+import static android.os.PowerWhitelistManager.REASON_BACKGROUND_FGS_PERMISSION;
+import static android.os.PowerWhitelistManager.REASON_COMPANION_DEVICE_MANAGER;
+import static android.os.PowerWhitelistManager.REASON_DENIED;
+import static android.os.PowerWhitelistManager.REASON_DEVICE_DEMO_MODE;
+import static android.os.PowerWhitelistManager.REASON_DEVICE_OWNER;
+import static android.os.PowerWhitelistManager.REASON_EXEMPTED_PACKAGE;
+import static android.os.PowerWhitelistManager.REASON_FGS_BINDING;
+import static android.os.PowerWhitelistManager.REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
+import static android.os.PowerWhitelistManager.REASON_INSTR_BACKGROUND_FGS_PERMISSION;
+import static android.os.PowerWhitelistManager.REASON_PROC_STATE_PERSISTENT;
+import static android.os.PowerWhitelistManager.REASON_PROC_STATE_PERSISTENT_UI;
+import static android.os.PowerWhitelistManager.REASON_PROC_STATE_TOP;
+import static android.os.PowerWhitelistManager.REASON_PROFILE_OWNER;
+import static android.os.PowerWhitelistManager.REASON_START_ACTIVITY_FLAG;
+import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
+import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALLOW_LISTED;
+import static android.os.PowerWhitelistManager.REASON_SYSTEM_UID;
+import static android.os.PowerWhitelistManager.REASON_UID_VISIBLE;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
+import static android.os.PowerWhitelistManager.getReasonCodeFromProcState;
+import static android.os.PowerWhitelistManager.reasonCodeToString;
 import static android.os.Process.NFC_UID;
 import static android.os.Process.ROOT_UID;
 import static android.os.Process.SHELL_UID;
@@ -43,7 +68,6 @@
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 
-import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -86,6 +110,8 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.PowerWhitelistManager;
+import android.os.PowerWhitelistManager.ReasonCode;
 import android.os.Process;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
@@ -130,8 +156,6 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Comparator;
@@ -152,58 +176,6 @@
 
     private static final boolean SHOW_DUNGEON_NOTIFICATION = false;
 
-    public static final int FGS_FEATURE_DENIED = 0;
-    public static final int FGS_FEATURE_ALLOWED_BY_UID_STATE = 1;
-    public static final int FGS_FEATURE_ALLOWED_BY_PROC_STATE = 2;
-    public static final int FGS_FEATURE_ALLOWED_BY_UID_VISIBLE = 3;
-    public static final int FGS_FEATURE_ALLOWED_BY_FLAG = 4;
-    public static final int FGS_FEATURE_ALLOWED_BY_SYSTEM_UID = 5;
-    public static final int FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION = 6;
-    public static final int FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION = 7;
-    public static final int FGS_FEATURE_ALLOWED_BY_ACTIVITY_TOKEN = 8;
-    public static final int FGS_FEATURE_ALLOWED_BY_FGS_TOKEN = 9;
-    public static final int FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION = 10;
-    public static final int FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION = 12;
-    public static final int FGS_FEATURE_ALLOWED_BY_ALLOWLIST = 13;
-    public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER = 14;
-    public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST = 15;
-    public static final int FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION = 16;
-    public static final int FGS_FEATURE_ALLOWED_BY_FGS_BINDING = 17;
-    public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE = 18;
-    public static final int FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD = 19;
-    public static final int FGS_FEATURE_ALLOWED_BY_EXEMPTED_PACKAGES = 20;
-    public static final int FGS_FEATURE_ALLOWED_BY_ACTIVITY_STARTER = 21;
-    public static final int FGS_FEATURE_ALLOWED_BY_COMPANION_APP = 22;
-    public static final int FGS_FEATURE_ALLOWED_BY_PROFILE_OWNER = 23;
-
-    @IntDef(flag = true, prefix = { "FGS_FEATURE_" }, value = {
-            FGS_FEATURE_DENIED,
-            FGS_FEATURE_ALLOWED_BY_UID_STATE,
-            FGS_FEATURE_ALLOWED_BY_PROC_STATE,
-            FGS_FEATURE_ALLOWED_BY_UID_VISIBLE,
-            FGS_FEATURE_ALLOWED_BY_FLAG,
-            FGS_FEATURE_ALLOWED_BY_SYSTEM_UID,
-            FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION,
-            FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION,
-            FGS_FEATURE_ALLOWED_BY_ACTIVITY_TOKEN,
-            FGS_FEATURE_ALLOWED_BY_FGS_TOKEN,
-            FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION,
-            FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION,
-            FGS_FEATURE_ALLOWED_BY_ALLOWLIST,
-            FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER,
-            FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST,
-            FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION,
-            FGS_FEATURE_ALLOWED_BY_FGS_BINDING,
-            FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE,
-            FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD,
-            FGS_FEATURE_ALLOWED_BY_EXEMPTED_PACKAGES,
-            FGS_FEATURE_ALLOWED_BY_ACTIVITY_STARTER,
-            FGS_FEATURE_ALLOWED_BY_COMPANION_APP,
-            FGS_FEATURE_ALLOWED_BY_PROFILE_OWNER
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface FgsFeatureRetCode {}
-
     // How long we wait for a service to finish executing.
     static final int SERVICE_TIMEOUT = 20*1000;
 
@@ -275,7 +247,7 @@
 
     AppWidgetManagerInternal mAppWidgetManagerInternal;
 
-    // white listed packageName.
+    // allowlisted packageName.
     ArraySet<String> mAllowListWhileInUsePermissionInFgs = new ArraySet<>();
 
     // TODO: remove this after feature development is done
@@ -675,7 +647,7 @@
 
         if (fgRequired) {
             logFgsBackgroundStart(r);
-            if (r.mAllowStartForeground == FGS_FEATURE_DENIED && isBgFgsRestrictionEnabled(r)) {
+            if (r.mAllowStartForeground == REASON_DENIED && isBgFgsRestrictionEnabled(r)) {
                 String msg = "startForegroundService() not allowed due to "
                         + "mAllowStartForeground false: service "
                         + r.shortInstanceName;
@@ -1768,8 +1740,7 @@
 
                 if (!ignoreForeground) {
                     logFgsBackgroundStart(r);
-                    if (r.mAllowStartForeground == FGS_FEATURE_DENIED
-                            && isBgFgsRestrictionEnabled(r)) {
+                    if (r.mAllowStartForeground == REASON_DENIED && isBgFgsRestrictionEnabled(r)) {
                         final String msg = "Service.startForeground() not allowed due to "
                                 + "mAllowStartForeground false: service "
                                 + r.shortInstanceName;
@@ -2250,7 +2221,7 @@
         psr.mAllowlistManager = false;
         for (int i = psr.numberOfRunningServices() - 1; i >= 0; i--) {
             ServiceRecord sr = psr.getRunningServiceAt(i);
-            if (sr.whitelistManager) {
+            if (sr.allowlistManager) {
                 psr.mAllowlistManager = true;
                 break;
             }
@@ -2261,7 +2232,7 @@
         final ProcessServiceRecord psr = service.app.mServices;
         psr.stopService(service);
         psr.updateBoundClientUids();
-        if (service.whitelistManager) {
+        if (service.allowlistManager) {
             updateAllowlistManagerLocked(psr);
         }
     }
@@ -2483,7 +2454,7 @@
                 clientPsr.setHasAboveClient(true);
             }
             if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
-                s.whitelistManager = true;
+                s.allowlistManager = true;
             }
             if ((flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) {
                 s.setAllowedBgActivityStartsByBinding(true);
@@ -2520,7 +2491,7 @@
                 if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
                     servicePsr.setTreatLikeActivity(true);
                 }
-                if (s.whitelistManager) {
+                if (s.allowlistManager) {
                     servicePsr.mAllowlistManager = true;
                 }
                 // This could have made the service more important.
@@ -2949,7 +2920,6 @@
                     final ServiceRestarter res = new ServiceRestarter();
                     r = new ServiceRecord(mAm, className, name, definingPackageName,
                             definingUid, filter, sInfo, callingFromFg, res);
-                    r.mRecentCallingPackage = callingPackage;
                     res.setService(r);
                     smap.mServicesByInstanceName.put(name, r);
                     smap.mServicesByIntent.put(filter, r);
@@ -2978,6 +2948,8 @@
             }
         }
         if (r != null) {
+            r.mRecentCallingPackage = callingPackage;
+            r.mRecentCallingUid = callingUid;
             if (!mAm.validateAssociationAllowedLocked(callingPackage, callingUid, r.packageName,
                     r.appInfo.uid)) {
                 String msg = "association not allowed between packages "
@@ -3440,12 +3412,13 @@
 
         if (r.fgRequired) {
             if (DEBUG_FOREGROUND_SERVICE) {
-                Slog.v(TAG, "Whitelisting " + UserHandle.formatUid(r.appInfo.uid)
+                Slog.v(TAG, "Allowlisting " + UserHandle.formatUid(r.appInfo.uid)
                         + " for fg-service launch");
             }
             mAm.tempAllowlistUidLocked(r.appInfo.uid,
-                    SERVICE_START_FOREGROUND_TIMEOUT, "fg-service-launch",
-                    BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED);
+                    SERVICE_START_FOREGROUND_TIMEOUT, PowerWhitelistManager.REASON_SERVICE_LAUNCH,
+                    "fg-service-launch", TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                    r.mRecentCallingUid);
         }
 
         if (!mPendingServices.contains(r)) {
@@ -3551,7 +3524,7 @@
             }
         }
 
-        if (r.whitelistManager) {
+        if (r.allowlistManager) {
             psr.mAllowlistManager = true;
         }
 
@@ -3868,6 +3841,8 @@
                     r.name.getClassName());
             stopServiceAndUpdateAllowlistManagerLocked(r);
             if (r.app.getThread() != null) {
+                // Bump the process to the top of LRU list
+                mAm.updateLruProcessLocked(r.app, false, null);
                 updateServiceForegroundLocked(r.app.mServices, false);
                 try {
                     bumpServiceExecutingLocked(r, false, "destroy");
@@ -3941,11 +3916,11 @@
             if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
                 psr.updateHasAboveClientLocked();
             }
-            // If this connection requested whitelist management, see if we should
+            // If this connection requested allowlist management, see if we should
             // now clear that state.
             if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
-                s.updateWhitelistManager();
-                if (!s.whitelistManager && s.app != null) {
+                s.updateAllowlistManager();
+                if (!s.allowlistManager && s.app != null) {
                     updateAllowlistManagerLocked(s.app.mServices);
                 }
             }
@@ -5400,13 +5375,13 @@
         }
 
         if (!r.mAllowWhileInUsePermissionInFgs
-                || (r.mAllowStartForeground == FGS_FEATURE_DENIED)) {
-            final @FgsFeatureRetCode int allowWhileInUse = shouldAllowFgsWhileInUsePermissionLocked(
+                || (r.mAllowStartForeground == REASON_DENIED)) {
+            final @ReasonCode int allowWhileInUse = shouldAllowFgsWhileInUsePermissionLocked(
                     callingPackage, callingPid, callingUid, r, allowBackgroundActivityStarts);
             if (!r.mAllowWhileInUsePermissionInFgs) {
-                r.mAllowWhileInUsePermissionInFgs = (allowWhileInUse != FGS_FEATURE_DENIED);
+                r.mAllowWhileInUsePermissionInFgs = (allowWhileInUse != REASON_DENIED);
             }
-            if (r.mAllowStartForeground == FGS_FEATURE_DENIED) {
+            if (r.mAllowStartForeground == REASON_DENIED) {
                 r.mAllowStartForeground = shouldAllowFgsStartForegroundLocked(allowWhileInUse,
                         callingPackage, callingPid, callingUid, intent, r,
                         allowBackgroundActivityStarts);
@@ -5420,37 +5395,37 @@
      * @param callingPackage caller app's package name.
      * @param callingUid caller app's uid.
      * @param r the service to start.
-     * @return {@link FgsFeatureRetCode}
+     * @return {@link ReasonCode}
      */
-    private @FgsFeatureRetCode int shouldAllowFgsWhileInUsePermissionLocked(String callingPackage,
+    private @ReasonCode int shouldAllowFgsWhileInUsePermissionLocked(String callingPackage,
             int callingPid, int callingUid, ServiceRecord r,
             boolean allowBackgroundActivityStarts) {
-        int ret = FGS_FEATURE_DENIED;
+        int ret = REASON_DENIED;
 
         final int uidState = mAm.getUidStateLocked(callingUid);
-        if (ret == FGS_FEATURE_DENIED) {
+        if (ret == REASON_DENIED) {
             // Is the calling UID at PROCESS_STATE_TOP or above?
             if (uidState <= PROCESS_STATE_TOP) {
-                ret = FGS_FEATURE_ALLOWED_BY_UID_STATE;
+                ret = getReasonCodeFromProcState(uidState);
             }
         }
 
-        if (ret == FGS_FEATURE_DENIED) {
+        if (ret == REASON_DENIED) {
             // Does the calling UID have any visible activity?
             final boolean isCallingUidVisible = mAm.mAtmInternal.isUidForeground(callingUid);
             if (isCallingUidVisible) {
-                ret = FGS_FEATURE_ALLOWED_BY_UID_VISIBLE;
+                ret = REASON_UID_VISIBLE;
             }
         }
 
-        if (ret == FGS_FEATURE_DENIED) {
+        if (ret == REASON_DENIED) {
             // Is the allow activity background start flag on?
             if (allowBackgroundActivityStarts) {
-                ret = FGS_FEATURE_ALLOWED_BY_FLAG;
+                ret = REASON_START_ACTIVITY_FLAG;
             }
         }
 
-        if (ret == FGS_FEATURE_DENIED) {
+        if (ret == REASON_DENIED) {
             boolean isCallerSystem = false;
             final int callingAppId = UserHandle.getAppId(callingUid);
             switch (callingAppId) {
@@ -5466,15 +5441,15 @@
             }
 
             if (isCallerSystem) {
-                ret = FGS_FEATURE_ALLOWED_BY_SYSTEM_UID;
+                ret = REASON_SYSTEM_UID;
             }
         }
 
-        if (ret == FGS_FEATURE_DENIED) {
+        if (ret == REASON_DENIED) {
             final Integer allowedType = mAm.mProcessList.searchEachLruProcessesLOSP(false, pr -> {
                 if (pr.uid == callingUid) {
                     if (pr.getWindowProcessController().areBackgroundFgsStartsAllowed()) {
-                        return FGS_FEATURE_ALLOWED_BY_ACTIVITY_STARTER;
+                        return REASON_ACTIVITY_STARTER;
                     }
                 }
                 return null;
@@ -5484,35 +5459,35 @@
             }
         }
 
-        if (ret == FGS_FEATURE_DENIED) {
+        if (ret == REASON_DENIED) {
             if (r.app != null) {
                 ActiveInstrumentation instr = r.app.getActiveInstrumentation();
                 if (instr != null && instr.mHasBackgroundActivityStartsPermission) {
-                    ret = FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
+                    ret = REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
                 }
             }
         }
 
-        if (ret == FGS_FEATURE_DENIED) {
+        if (ret == REASON_DENIED) {
             if (mAm.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
                     == PERMISSION_GRANTED) {
-                ret = FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION;
+                ret = REASON_BACKGROUND_ACTIVITY_PERMISSION;
             }
         }
 
-        if (ret == FGS_FEATURE_DENIED) {
+        if (ret == REASON_DENIED) {
             final boolean isAllowedPackage =
                     mAllowListWhileInUsePermissionInFgs.contains(callingPackage);
             if (isAllowedPackage) {
-                ret = FGS_FEATURE_ALLOWED_BY_ALLOWLIST;
+                ret = REASON_ALLOWLISTED_PACKAGE;
             }
         }
 
-        if (ret == FGS_FEATURE_DENIED) {
+        if (ret == REASON_DENIED) {
             // Is the calling UID a device owner app?
             final boolean isDeviceOwner = mAm.mInternal.isDeviceOwner(callingUid);
             if (isDeviceOwner) {
-                ret = FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER;
+                ret = REASON_DEVICE_OWNER;
             }
         }
         return ret;
@@ -5527,38 +5502,40 @@
      * @param callingUid caller app's uid.
      * @param intent intent to start/bind service.
      * @param r the service to start.
-     * @return {@link FgsFeatureRetCode}
+     * @return {@link ReasonCode}
      */
-    private @FgsFeatureRetCode int shouldAllowFgsStartForegroundLocked(
-            @FgsFeatureRetCode int allowWhileInUse, String callingPackage, int callingPid,
+    private @ReasonCode int shouldAllowFgsStartForegroundLocked(
+            @ReasonCode int allowWhileInUse, String callingPackage, int callingPid,
             int callingUid, Intent intent, ServiceRecord r, boolean allowBackgroundActivityStarts) {
         int ret = allowWhileInUse;
+        FgsStartTempAllowList.TempFgsAllowListEntry tempAllowListReason =
+                r.mInfoTempFgsAllowListReason = mAm.isAllowlistedForFgsStartLOSP(callingUid);
 
         final StringBuilder sb = new StringBuilder(64);
         final int uidState = mAm.getUidStateLocked(callingUid);
-        if (ret == FGS_FEATURE_DENIED) {
+        if (ret == REASON_DENIED) {
             // Is the calling UID at PROCESS_STATE_TOP or above?
             if (uidState <= PROCESS_STATE_TOP) {
                 sb.append("uidState=").append(uidState);
-                ret = FGS_FEATURE_ALLOWED_BY_UID_STATE;
+                ret = getReasonCodeFromProcState(uidState);
             }
         }
 
-        if (ret == FGS_FEATURE_DENIED) {
+        if (ret == REASON_DENIED) {
             final Integer allowedType = mAm.mProcessList.searchEachLruProcessesLOSP(false, app -> {
                 if (app.uid == callingUid) {
                     final ProcessStateRecord state = app.mState;
-                    if (state.getAllowedStartFgs() != FGS_FEATURE_DENIED) {
+                    if (state.getAllowedStartFgs() != REASON_DENIED) {
                         return state.getAllowedStartFgs();
                     } else if (state.isAllowedStartFgsState()) {
-                        return FGS_FEATURE_ALLOWED_BY_PROC_STATE;
+                        return getReasonCodeFromProcState(state.getAllowStartFgsState());
                     } else if (state.areBackgroundFgsStartsAllowedByToken()) {
-                        return FGS_FEATURE_ALLOWED_BY_FGS_BINDING;
+                        return REASON_FGS_BINDING;
                     } else {
                         final ActiveInstrumentation instr = app.getActiveInstrumentation();
                         if (instr != null
                                 && instr.mHasBackgroundForegroundServiceStartsPermission) {
-                            return FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION;
+                            return REASON_INSTR_BACKGROUND_FGS_PERMISSION;
                         }
                     }
                 }
@@ -5569,55 +5546,59 @@
             }
         }
 
-        if (ret == FGS_FEATURE_DENIED) {
+        if (ret == REASON_DENIED) {
             if (mAm.checkPermission(START_FOREGROUND_SERVICES_FROM_BACKGROUND, callingPid,
                     callingUid) == PERMISSION_GRANTED) {
-                ret = FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION;
+                ret = REASON_BACKGROUND_FGS_PERMISSION;
             }
         }
 
-        if (ret == FGS_FEATURE_DENIED) {
+        if (ret == REASON_DENIED) {
             if (mAm.checkPermission(SYSTEM_ALERT_WINDOW, callingPid,
                     callingUid) == PERMISSION_GRANTED) {
-                ret = FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION;
+                ret = REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
             }
         }
 
-        if (ret == FGS_FEATURE_DENIED) {
-            if (mAm.isAllowlistedForFgsStartLOSP(callingUid)) {
-                // uid is on DeviceIdleController's user/system allowlist
-                // or AMS's FgsStartTempAllowList.
-                ret = FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST;
+        if (ret == REASON_DENIED) {
+            FgsStartTempAllowList.TempFgsAllowListEntry entry =
+                    mAm.isAllowlistedForFgsStartLOSP(callingUid);
+            if (entry != null) {
+                if (entry == ActivityManagerService.FAKE_TEMP_ALLOWLIST_ENTRY) {
+                    ret = REASON_SYSTEM_ALLOW_LISTED;
+                } else {
+                    ret = entry.mReasonCode;
+                }
             }
         }
 
-        if (ret == FGS_FEATURE_DENIED) {
+        if (ret == REASON_DENIED) {
             if (UserManager.isDeviceInDemoMode(mAm.mContext)) {
-                ret = FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE;
+                ret = REASON_DEVICE_DEMO_MODE;
             }
         }
 
-        if (ret == FGS_FEATURE_DENIED) {
+        if (ret == REASON_DENIED) {
             // Is the calling UID a profile owner app?
             final boolean isProfileOwner = mAm.mInternal.isProfileOwner(callingUid);
             if (isProfileOwner) {
-                ret = FGS_FEATURE_ALLOWED_BY_PROFILE_OWNER;
+                ret = REASON_PROFILE_OWNER;
             }
         }
 
         // NOTE this should always be the last check.
-        if (ret == FGS_FEATURE_DENIED) {
+        if (ret == REASON_DENIED) {
             if (isPackageExemptedFromFgsRestriction(r.appInfo.packageName, r.appInfo.uid)
                     || isPackageExemptedFromFgsRestriction(callingPackage, callingUid)) {
-                ret = FGS_FEATURE_ALLOWED_BY_EXEMPTED_PACKAGES;
+                ret = REASON_EXEMPTED_PACKAGE;
             }
         }
 
-        if (ret == FGS_FEATURE_DENIED) {
+        if (ret == REASON_DENIED) {
             final boolean isCompanionApp = mAm.mInternal.isAssociatedCompanionApp(
                     UserHandle.getUserId(callingUid), callingUid);
             if (isCompanionApp) {
-                ret = FGS_FEATURE_ALLOWED_BY_COMPANION_APP;
+                ret = REASON_COMPANION_DEVICE_MANAGER;
             }
         }
 
@@ -5626,7 +5607,15 @@
                         + "; callingUid: " + callingUid
                         + "; uidState: " + ProcessList.makeProcStateString(uidState)
                         + "; intent: " + intent
-                        + "; code:" + fgsCodeToString(ret)
+                        + "; code:" + reasonCodeToString(ret)
+                        + "; tempAllowListReason:<" +
+                        (tempAllowListReason == null ? null :
+                                (tempAllowListReason.mReason
+                                + ",reasonCode:"
+                                + reasonCodeToString(tempAllowListReason.mReasonCode)
+                                + ",duration:" + tempAllowListReason.mDuration
+                                + ",callingUid:" + tempAllowListReason.mCallingUid))
+                        + ">"
                         + "; extra:" + sb.toString()
                         + "; targetSdkVersion:" + r.appInfo.targetSdkVersion
                         + "]";
@@ -5660,62 +5649,11 @@
         return CompatChanges.isChangeEnabled(FGS_BG_START_USE_EXEMPTION_LIST_CHANGE_ID, uid);
     }
 
-    static String fgsCodeToString(@FgsFeatureRetCode int code) {
-        switch (code) {
-            case FGS_FEATURE_DENIED:
-                return "DENIED";
-            case FGS_FEATURE_ALLOWED_BY_UID_STATE:
-                return "ALLOWED_BY_UID_STATE";
-            case FGS_FEATURE_ALLOWED_BY_PROC_STATE:
-                return "ALLOWED_BY_PROC_STATE";
-            case FGS_FEATURE_ALLOWED_BY_UID_VISIBLE:
-                return "ALLOWED_BY_UID_VISIBLE";
-            case FGS_FEATURE_ALLOWED_BY_FLAG:
-                return "ALLOWED_BY_FLAG";
-            case FGS_FEATURE_ALLOWED_BY_SYSTEM_UID:
-                return "ALLOWED_BY_SYSTEM_UID";
-            case FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION:
-                return "ALLOWED_BY_INSTR_BACKGROUND_ACTIVITY_PERMISSION";
-            case FGS_FEATURE_ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION:
-                return "ALLOWED_BY_INSTR_BACKGROUND_FGS_PERMISSION";
-            case FGS_FEATURE_ALLOWED_BY_ACTIVITY_TOKEN:
-                return "ALLOWED_BY_ACTIVITY_TOKEN";
-            case FGS_FEATURE_ALLOWED_BY_FGS_TOKEN:
-                return "ALLOWED_BY_FGS_TOKEN";
-            case FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION:
-                return "ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION";
-            case FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION:
-                return "ALLOWED_BY_BACKGROUND_FGS_PERMISSION";
-            case FGS_FEATURE_ALLOWED_BY_ALLOWLIST:
-                return "ALLOWED_BY_ALLOWLIST";
-            case FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER:
-                return "ALLOWED_BY_DEVICE_OWNER";
-            case FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST:
-                return "ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST";
-            case FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION:
-                return "ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION";
-            case FGS_FEATURE_ALLOWED_BY_FGS_BINDING:
-                return "ALLOWED_BY_FGS_BINDING";
-            case FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE:
-                return "ALLOWED_BY_DEVICE_DEMO_MODE";
-            case FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD:
-                return "ALLOWED_BY_PROCESS_RECORD";
-            case FGS_FEATURE_ALLOWED_BY_EXEMPTED_PACKAGES:
-                return "FGS_FEATURE_ALLOWED_BY_EXEMPTED_PACKAGES";
-            case FGS_FEATURE_ALLOWED_BY_ACTIVITY_STARTER:
-                return "ALLOWED_BY_ACTIVITY_STARTER";
-            case FGS_FEATURE_ALLOWED_BY_COMPANION_APP:
-                return "ALLOWED_BY_COMPANION_APP";
-            case FGS_FEATURE_ALLOWED_BY_PROFILE_OWNER:
-                return "ALLOWED_BY_PROFILE_OWNER";
-            default:
-                return "";
-        }
-    }
-
-    private static boolean isFgsBgStart(@FgsFeatureRetCode int code) {
-        return code != FGS_FEATURE_ALLOWED_BY_UID_STATE
-                && code != FGS_FEATURE_ALLOWED_BY_UID_VISIBLE;
+    private static boolean isFgsBgStart(@ReasonCode int code) {
+        return code != REASON_PROC_STATE_PERSISTENT
+                && code != REASON_PROC_STATE_PERSISTENT_UI
+                && code != REASON_PROC_STATE_TOP
+                && code != REASON_UID_VISIBLE;
     }
 
     // TODO: remove this notification after feature development is done
@@ -5754,10 +5692,10 @@
         }
         if (!r.mLoggedInfoAllowStartForeground) {
             final String msg = "Background started FGS: "
-                    + ((r.mAllowStartForeground != FGS_FEATURE_DENIED) ? "Allowed " : "Disallowed ")
+                    + ((r.mAllowStartForeground != REASON_DENIED) ? "Allowed " : "Disallowed ")
                     + r.mInfoAllowStartForeground;
             Slog.wtfQuiet(TAG, msg);
-            if (r.mAllowStartForeground != FGS_FEATURE_DENIED) {
+            if (r.mAllowStartForeground != REASON_DENIED) {
                 Slog.i(TAG, msg);
             } else {
                 Slog.w(TAG, msg);
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index 171b20c..9d1c838 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -68,7 +68,7 @@
     static final boolean DEBUG_UID_OBSERVERS = DEBUG_ALL || false;
     static final boolean DEBUG_USAGE_STATS = DEBUG_ALL || false;
     static final boolean DEBUG_PERMISSIONS_REVIEW = DEBUG_ALL || false;
-    static final boolean DEBUG_WHITELISTS = DEBUG_ALL || false;
+    static final boolean DEBUG_ALLOWLISTS = DEBUG_ALL || false;
 
     static final String POSTFIX_BACKUP = (APPEND_CATEGORY_NAME) ? "_Backup" : "";
     static final String POSTFIX_BROADCAST = (APPEND_CATEGORY_NAME) ? "_Broadcast" : "";
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 29b85ac..e8a4fa2 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -33,7 +33,6 @@
 import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
 import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
 import static android.app.AppOpsManager.OP_NONE;
-import static android.app.BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
 import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT;
 import static android.content.pm.PackageManager.GET_SHARED_LIBRARY_FILES;
 import static android.content.pm.PackageManager.MATCH_ALL;
@@ -50,8 +49,12 @@
 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
 import static android.os.IServiceManager.DUMP_FLAG_PROTO;
+import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALLOW_LISTED;
+import static android.os.PowerWhitelistManager.REASON_UNKNOWN;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
 import static android.os.Process.BLUETOOTH_UID;
 import static android.os.Process.FIRST_APPLICATION_UID;
+import static android.os.Process.INVALID_UID;
 import static android.os.Process.NETWORK_STACK_UID;
 import static android.os.Process.NFC_UID;
 import static android.os.Process.PHONE_UID;
@@ -101,7 +104,7 @@
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_WHITELISTS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALLOWLISTS;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BACKUP;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP;
@@ -142,6 +145,8 @@
 import android.app.Activity;
 import android.app.ActivityClient;
 import android.app.ActivityManager;
+import android.app.ActivityManager.PendingIntentInfo;
+import android.app.ActivityManager.ProcessCapability;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManagerInternal;
 import android.app.ActivityTaskManager.RootTaskInfo;
@@ -251,6 +256,7 @@
 import android.os.PowerManager;
 import android.os.PowerManager.ServiceType;
 import android.os.PowerManagerInternal;
+import android.os.PowerWhitelistManager.ReasonCode;
 import android.os.PowerWhitelistManager.TempAllowListType;
 import android.os.Process;
 import android.os.RemoteCallback;
@@ -305,6 +311,7 @@
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.ProcessMap;
 import com.android.internal.app.SystemUserHomeActivity;
+import com.android.internal.app.procstats.ProcessState;
 import com.android.internal.app.procstats.ProcessStats;
 import com.android.internal.content.PackageHelper;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
@@ -622,7 +629,7 @@
      */
     private volatile String mDeviceOwnerName;
 
-    private volatile int mDeviceOwnerUid = Process.INVALID_UID;
+    private volatile int mDeviceOwnerUid = INVALID_UID;
 
     /**
      * Map userId to its companion app uids.
@@ -1148,13 +1155,13 @@
     DeviceIdleInternal mLocalDeviceIdleController;
 
     /**
-     * Power-save whitelisted app-ids (not including except-idle-whitelisted ones).
+     * Power-save allowlisted app-ids (not including except-idle-allowlisted ones).
      */
     @CompositeRWLock({"this", "mProcLock"})
     int[] mDeviceIdleAllowlist = new int[0];
 
     /**
-     * Power-save whitelisted app-ids (including except-idle-whitelisted ones).
+     * Power-save allowlisted app-ids (including except-idle-allowlisted ones).
      */
     @CompositeRWLock({"this", "mProcLock"})
     int[] mDeviceIdleExceptIdleAllowlist = new int[0];
@@ -1170,20 +1177,27 @@
         final long duration;
         final String tag;
         final int type;
+        final @ReasonCode int reasonCode;
 
-        PendingTempAllowlist(int targetUid, long duration, String tag, int type) {
+        PendingTempAllowlist(int targetUid, long duration, @ReasonCode int reasonCode, String tag,
+                int type) {
             this.targetUid = targetUid;
             this.duration = duration;
             this.tag = tag;
             this.type = type;
+            this.reasonCode = reasonCode;
         }
 
         void dumpDebug(ProtoOutputStream proto, long fieldId) {
             final long token = proto.start(fieldId);
-            proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.TARGET_UID, targetUid);
-            proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.DURATION_MS, duration);
+            proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.TARGET_UID,
+                    targetUid);
+            proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.DURATION_MS,
+                    duration);
             proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.TAG, tag);
             proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.TYPE, type);
+            proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.REASON_CODE,
+                    reasonCode);
             proto.end(token);
         }
     }
@@ -1197,6 +1211,9 @@
     @CompositeRWLock({"this", "mProcLock"})
     final FgsStartTempAllowList mFgsStartTempAllowList = new FgsStartTempAllowList();
 
+    static final FgsStartTempAllowList.TempFgsAllowListEntry FAKE_TEMP_ALLOWLIST_ENTRY = new
+            FgsStartTempAllowList.TempFgsAllowListEntry(Long.MAX_VALUE, Long.MAX_VALUE,
+            REASON_SYSTEM_ALLOW_LISTED, "", INVALID_UID);
     /**
      * Information about and control over application operations
      */
@@ -1818,6 +1835,15 @@
         ncl.start();
     }
 
+    /**
+     * Sets a policy for handling app ops.
+     *
+     * @param appOpsPolicy The policy.
+     */
+    public void setAppOpsPolicy(@Nullable CheckOpsDelegate appOpsPolicy) {
+        mAppOpsService.setAppOpsPolicy(appOpsPolicy);
+    }
+
     public IAppOpsService getAppOpsService() {
         return mAppOpsService;
     }
@@ -3777,10 +3803,11 @@
                                 mi.getTotalUss(), mi.getTotalRss(), false,
                                 ProcessStats.ADD_PSS_EXTERNAL_SLOW, duration);
                         proc.getPkgList().forEachPackageProcessStats(holder -> {
+                            final ProcessState state = holder.state;
                             FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_MEMORY_STAT_REPORTED,
                                     proc.info.uid,
-                                    holder.state.getName(),
-                                    holder.state.getPackage(),
+                                    state != null ? state.getName() : proc.processName,
+                                    state != null ? state.getPackage() : proc.info.packageName,
                                     mi.getTotalPss(),
                                     mi.getTotalUss(),
                                     mi.getTotalRss(),
@@ -4816,12 +4843,12 @@
     }
 
     @Override
-    public int sendIntentSender(IIntentSender target, IBinder whitelistToken, int code,
+    public int sendIntentSender(IIntentSender target, IBinder allowlistToken, int code,
             Intent intent, String resolvedType,
             IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
         if (target instanceof PendingIntentRecord) {
             return ((PendingIntentRecord)target).sendWithResult(code, intent, resolvedType,
-                    whitelistToken, finishedReceiver, requiredPermission, options);
+                    allowlistToken, finishedReceiver, requiredPermission, options);
         } else {
             if (intent == null) {
                 // Weird case: someone has given us their own custom IIntentSender, and now
@@ -4833,7 +4860,7 @@
                 intent = new Intent(Intent.ACTION_MAIN);
             }
             try {
-                target.send(code, intent, resolvedType, whitelistToken, null,
+                target.send(code, intent, resolvedType, allowlistToken, null,
                         requiredPermission, options);
             } catch (RemoteException e) {
             }
@@ -4858,19 +4885,6 @@
     }
 
     @Override
-    public String getPackageForIntentSender(IIntentSender pendingResult) {
-        if (!(pendingResult instanceof PendingIntentRecord)) {
-            return null;
-        }
-        try {
-            PendingIntentRecord res = (PendingIntentRecord)pendingResult;
-            return res.key.packageName;
-        } catch (ClassCastException e) {
-        }
-        return null;
-    }
-
-    @Override
     public void registerIntentSenderCancelListener(IIntentSender sender, IResultReceiver receiver) {
         mPendingIntentController.registerIntentSenderCancelListener(sender, receiver);
     }
@@ -4882,15 +4896,17 @@
     }
 
     @Override
-    public int getUidForIntentSender(IIntentSender sender) {
+    public PendingIntentInfo getInfoForIntentSender(IIntentSender sender) {
         if (sender instanceof PendingIntentRecord) {
-            try {
-                PendingIntentRecord res = (PendingIntentRecord)sender;
-                return res.uid;
-            } catch (ClassCastException e) {
-            }
+            PendingIntentRecord res = (PendingIntentRecord) sender;
+            return new PendingIntentInfo(
+                    res.key.packageName,
+                    res.uid,
+                    (res.key.flags & PendingIntent.FLAG_IMMUTABLE) != 0,
+                    res.key.type);
+        } else {
+            throw new IllegalArgumentException();
         }
-        return -1;
     }
 
     @Override
@@ -4916,15 +4932,6 @@
     }
 
     @Override
-    public boolean isIntentSenderImmutable(IIntentSender pendingResult) {
-        if (pendingResult instanceof PendingIntentRecord) {
-            final PendingIntentRecord res = (PendingIntentRecord) pendingResult;
-            return (res.key.flags & PendingIntent.FLAG_IMMUTABLE) != 0;
-        }
-        return false;
-    }
-
-    @Override
     public boolean isIntentSenderAnActivity(IIntentSender pendingResult) {
         if (!(pendingResult instanceof PendingIntentRecord)) {
             return false;
@@ -4941,33 +4948,6 @@
     }
 
     @Override
-    public boolean isIntentSenderAForegroundService(IIntentSender pendingResult) {
-        if (pendingResult instanceof PendingIntentRecord) {
-            final PendingIntentRecord res = (PendingIntentRecord) pendingResult;
-            return res.key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE;
-        }
-        return false;
-    }
-
-    @Override
-    public boolean isIntentSenderAService(IIntentSender pendingResult) {
-        if (pendingResult instanceof PendingIntentRecord) {
-            final PendingIntentRecord res = (PendingIntentRecord) pendingResult;
-            return res.key.type == ActivityManager.INTENT_SENDER_SERVICE;
-        }
-        return false;
-    }
-
-    @Override
-    public boolean isIntentSenderABroadcast(IIntentSender pendingResult) {
-        if (pendingResult instanceof PendingIntentRecord) {
-            final PendingIntentRecord res = (PendingIntentRecord) pendingResult;
-            return res.key.type == ActivityManager.INTENT_SENDER_BROADCAST;
-        }
-        return false;
-    }
-
-    @Override
     public Intent getIntentForIntentSender(IIntentSender pendingResult) {
         enforceCallingPermission(Manifest.permission.GET_INTENT_SENDER_INTENT,
                 "getIntentForIntentSender()");
@@ -5448,7 +5428,7 @@
         }
         switch (appop) {
             case AppOpsManager.MODE_ALLOWED:
-                // If force-background-check is enabled, restrict all apps that aren't whitelisted.
+                // If force-background-check is enabled, restrict all apps that aren't allowlisted.
                 if (mForceBackgroundCheck &&
                         !UserHandle.isCore(uid) &&
                         !isOnDeviceIdleAllowlistLOSP(uid, /*allowExceptIdleToo=*/ true)) {
@@ -5484,7 +5464,7 @@
         if (uidOnBackgroundAllowlistLOSP(uid)) {
             if (DEBUG_BACKGROUND_CHECK) {
                 Slog.i(TAG, "App " + uid + "/" + packageName
-                        + " on background whitelist; not restricted in background");
+                        + " on background allowlist; not restricted in background");
             }
             return ActivityManager.APP_START_MODE_NORMAL;
         }
@@ -5493,7 +5473,7 @@
         if (isOnDeviceIdleAllowlistLOSP(uid, /*allowExceptIdleToo=*/ false)) {
             if (DEBUG_BACKGROUND_CHECK) {
                 Slog.i(TAG, "App " + uid + "/" + packageName
-                        + " on idle whitelist; not restricted in background");
+                        + " on idle allowlist; not restricted in background");
             }
             return ActivityManager.APP_START_MODE_NORMAL;
         }
@@ -5581,10 +5561,19 @@
                 || mPendingTempAllowlist.indexOfKey(uid) >= 0;
     }
 
+    /**
+     * Is the uid allowlisted to start FGS?
+     * @param uid
+     * @return a TempAllowListEntry if the uid is allowed.
+     *         null if the uid is not allowed.
+     */
+    @Nullable
     @GuardedBy(anyOf = {"this", "mProcLock"})
-    boolean isAllowlistedForFgsStartLOSP(int uid) {
-        return Arrays.binarySearch(mDeviceIdleExceptIdleAllowlist, UserHandle.getAppId(uid)) >= 0
-                || mFgsStartTempAllowList.isAllowed(uid);
+    FgsStartTempAllowList.TempFgsAllowListEntry isAllowlistedForFgsStartLOSP(int uid) {
+        if (Arrays.binarySearch(mDeviceIdleExceptIdleAllowlist, UserHandle.getAppId(uid)) >= 0) {
+            return FAKE_TEMP_ALLOWLIST_ENTRY;
+        }
+        return mFgsStartTempAllowList.getAllowedDurationAndReason(uid);
     }
 
     /**
@@ -6056,13 +6045,13 @@
     }
 
     @Override
-    public void backgroundWhitelistUid(final int uid) {
+    public void backgroundAllowlistUid(final int uid) {
         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
-            throw new SecurityException("Only the OS may call backgroundWhitelistUid()");
+            throw new SecurityException("Only the OS may call backgroundAllowlistUid()");
         }
 
         if (DEBUG_BACKGROUND_CHECK) {
-            Slog.i(TAG, "Adding uid " + uid + " to bg uid whitelist");
+            Slog.i(TAG, "Adding uid " + uid + " to bg uid allowlist");
         }
         synchronized (this) {
             synchronized (mProcLock) {
@@ -6632,6 +6621,18 @@
     }
 
     @Override
+    public @ProcessCapability int getUidProcessCapabilities(int uid, String callingPackage) {
+        if (!hasUsageStatsPermission(callingPackage)) {
+            enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
+                    "getUidProcessState");
+        }
+
+        synchronized (mProcLock) {
+            return mProcessList.getUidProcessCapabilityLOSP(uid);
+        }
+    }
+
+    @Override
     public void registerUidObserver(IUidObserver observer, int which, int cutpoint,
             String callingPackage) {
         if (!hasUsageStatsPermission(callingPackage)) {
@@ -7247,6 +7248,9 @@
             final long memoryGrowthThreshold =
                     Math.max(totalMemoryInKb / 100, MINIMUM_MEMORY_GROWTH_THRESHOLD);
             mProcessList.forEachLruProcessesLOSP(false, proc -> {
+                if (proc.getThread() == null) {
+                    return;
+                }
                 final ProcessProfileRecord pr = proc.mProfile;
                 final ProcessStateRecord state = proc.mState;
                 final int setProcState = state.getSetProcState();
@@ -8290,7 +8294,7 @@
         if (!TextUtils.isEmpty(packageName)) {
             final int uid = enforceDumpPermissionForPackage(packageName, userId, callingUid,
                       "getHistoricalProcessExitReasons");
-            if (uid != Process.INVALID_UID) {
+            if (uid != INVALID_UID) {
                 mProcessList.mAppExitInfoTracker.getExitInfo(
                         packageName, uid, pid, maxNum, results);
                 tombstoneService.collectTombstones(results, uid, pid, maxNum);
@@ -8324,7 +8328,7 @@
     int enforceDumpPermissionForPackage(String packageName, int userId, int callingUid,
             String function) {
         final long identity = Binder.clearCallingIdentity();
-        int uid = Process.INVALID_UID;
+        int uid = INVALID_UID;
         try {
             uid = mPackageManagerInt.getPackageUid(packageName,
                     MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId);
@@ -9216,6 +9220,8 @@
                     pw.println(ptw.tag);
                     pw.print(" ");
                     pw.print(ptw.type);
+                    pw.print(" ");
+                    pw.print(ptw.reasonCode);
                 }
             }
         }
@@ -10077,6 +10083,7 @@
             ProcessList.PERSISTENT_SERVICE_ADJ, ProcessList.FOREGROUND_APP_ADJ,
             ProcessList.VISIBLE_APP_ADJ,
             ProcessList.PERCEPTIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_LOW_APP_ADJ,
+            ProcessList.PERCEPTIBLE_MEDIUM_APP_ADJ,
             ProcessList.BACKUP_APP_ADJ, ProcessList.HEAVY_WEIGHT_APP_ADJ,
             ProcessList.SERVICE_ADJ, ProcessList.HOME_APP_ADJ,
             ProcessList.PREVIOUS_APP_ADJ, ProcessList.SERVICE_B_ADJ, ProcessList.CACHED_APP_MIN_ADJ
@@ -10084,7 +10091,7 @@
     static final String[] DUMP_MEM_OOM_LABEL = new String[] {
             "Native",
             "System", "Persistent", "Persistent Service", "Foreground",
-            "Visible", "Perceptible", "Perceptible Low",
+            "Visible", "Perceptible", "Perceptible Low", "Perceptible Medium",
             "Heavy Weight", "Backup",
             "A Services", "Home",
             "Previous", "B Services", "Cached"
@@ -10092,7 +10099,7 @@
     static final String[] DUMP_MEM_OOM_COMPACT_LABEL = new String[] {
             "native",
             "sys", "pers", "persvc", "fore",
-            "vis", "percept", "perceptl",
+            "vis", "percept", "perceptl", "perceptm",
             "heavy", "backup",
             "servicea", "home",
             "prev", "serviceb", "cached"
@@ -10400,6 +10407,8 @@
                     }
                     endTime = SystemClock.currentThreadTimeMillis();
                     hasSwapPss = mi.hasSwappedOutPss;
+                    memtrackGraphics = mi.getOtherPrivate(Debug.MemoryInfo.OTHER_GRAPHICS);
+                    memtrackGl = mi.getOtherPrivate(Debug.MemoryInfo.OTHER_GL);
                 } else {
                     reportType = ProcessStats.ADD_PSS_EXTERNAL;
                     startTime = SystemClock.currentThreadTimeMillis();
@@ -10551,6 +10560,8 @@
                         if (!Debug.getMemoryInfo(st.pid, info)) {
                             return;
                         }
+                        memtrackGraphics = info.getOtherPrivate(Debug.MemoryInfo.OTHER_GRAPHICS);
+                        memtrackGl = info.getOtherPrivate(Debug.MemoryInfo.OTHER_GL);
                     } else {
                         long pss = Debug.getPss(st.pid, tmpLong, memtrackTmp);
                         if (pss == 0) {
@@ -12568,7 +12579,7 @@
         BroadcastOptions brOptions = null;
         if (bOptions != null) {
             brOptions = new BroadcastOptions(bOptions);
-            if (brOptions.getTemporaryAppWhitelistDuration() > 0) {
+            if (brOptions.getTemporaryAppAllowlistDuration() > 0) {
                 // See if the caller is allowed to do this.  Note we are checking against
                 // the actual real caller (not whoever provided the operation as say a
                 // PendingIntent), because that who is actually supplied the arguments.
@@ -13950,7 +13961,7 @@
     }
 
     void noteUidProcessState(final int uid, final int state,
-                final @ActivityManager.ProcessCapability int capability) {
+                final @ProcessCapability int capability) {
         mBatteryStatsService.noteUidProcessState(uid, state);
         mAppOpsService.updateUidProcState(uid, state, capability);
         if (mTrackingAssociations) {
@@ -14001,6 +14012,9 @@
             final long uptimeSince = curUptime - mLastPowerCheckUptime;
             mLastPowerCheckUptime = curUptime;
             mProcessList.forEachLruProcessesLOSP(false, app -> {
+                if (app.getThread() == null) {
+                    return;
+                }
                 if (app.mState.getSetProcState() >= ActivityManager.PROCESS_STATE_HOME) {
                     int cpuLimit;
                     long checkDur = curUptime - app.mState.getWhenUnimportant();
@@ -14102,11 +14116,12 @@
                 mBatteryStatsService.reportExcessiveCpu(app.info.uid, app.processName,
                         uptimeSince, cputimeUsed);
                 app.getPkgList().forEachPackageProcessStats(holder -> {
+                    final ProcessState state = holder.state;
                     FrameworkStatsLog.write(
                             FrameworkStatsLog.EXCESSIVE_CPU_USAGE_REPORTED,
                             app.info.uid,
                             processName,
-                            holder.state.getPackage(),
+                            state != null ? state.getPackage() : app.info.packageName,
                             holder.appVersion);
                 });
                 return true;
@@ -14446,8 +14461,8 @@
      */
     @GuardedBy("this")
     void tempAllowlistForPendingIntentLocked(int callerPid, int callerUid, int targetUid,
-            long duration, int type, String tag) {
-        if (DEBUG_WHITELISTS) {
+            long duration, int type, @ReasonCode int reasonCode, String reason) {
+        if (DEBUG_ALLOWLISTS) {
             Slog.d(TAG, "tempAllowlistForPendingIntentLocked(" + callerPid + ", " + callerUid + ", "
                     + targetUid + ", " + duration + ", " + type + ")");
         }
@@ -14466,7 +14481,7 @@
                         != PackageManager.PERMISSION_GRANTED
                         && checkPermission(START_FOREGROUND_SERVICES_FROM_BACKGROUND, callerPid,
                         callerUid) != PackageManager.PERMISSION_GRANTED) {
-                    if (DEBUG_WHITELISTS) {
+                    if (DEBUG_ALLOWLISTS) {
                         Slog.d(TAG, "tempAllowlistForPendingIntentLocked() for target " + targetUid
                                 + ": pid " + callerPid + " is not allowed");
                     }
@@ -14475,22 +14490,23 @@
             }
         }
 
-        tempAllowlistUidLocked(targetUid, duration, tag, type);
+        tempAllowlistUidLocked(targetUid, duration, reasonCode, reason, type, callerUid);
     }
 
     /**
      * Allowlists {@code targetUid} to temporarily bypass Power Save mode.
      */
     @GuardedBy("this")
-    void tempAllowlistUidLocked(int targetUid, long duration, String tag, int type) {
+    void tempAllowlistUidLocked(int targetUid, long duration, @ReasonCode int reasonCode,
+            String reason, int type, int callingUid) {
         synchronized (mProcLock) {
             mPendingTempAllowlist.put(targetUid,
-                    new PendingTempAllowlist(targetUid, duration, tag, type));
+                    new PendingTempAllowlist(targetUid, duration, reasonCode, reason, type));
             setUidTempAllowlistStateLSP(targetUid, true);
             mUiHandler.obtainMessage(PUSH_TEMP_ALLOWLIST_UI_MSG).sendToTarget();
 
-            if (type == TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED) {
-                mFgsStartTempAllowList.add(targetUid, duration);
+            if (type == TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED) {
+                mFgsStartTempAllowList.add(targetUid, duration, reasonCode, reason, callingUid);
             }
         }
     }
@@ -14516,7 +14532,7 @@
             for (int i = 0; i < N; i++) {
                 PendingTempAllowlist ptw = list[i];
                 mLocalDeviceIdleController.addPowerSaveTempWhitelistAppDirect(ptw.targetUid,
-                        ptw.duration, ptw.type, true, ptw.tag);
+                        ptw.duration, ptw.type, true, ptw.reasonCode, ptw.tag);
             }
         }
 
@@ -15104,10 +15120,10 @@
         }
 
         @Override
-        public void setPendingIntentWhitelistDuration(IIntentSender target, IBinder whitelistToken,
-                long duration, int type) {
-            mPendingIntentController.setPendingIntentWhitelistDuration(target, whitelistToken,
-                    duration, type);
+        public void setPendingIntentAllowlistDuration(IIntentSender target, IBinder allowlistToken,
+                long duration, int type, @ReasonCode int reasonCode, @Nullable String reason) {
+            mPendingIntentController.setPendingIntentAllowlistDuration(target, allowlistToken,
+                    duration, type, reasonCode, reason);
         }
 
         @Override
@@ -15117,32 +15133,32 @@
 
         @Override
         public void setPendingIntentAllowBgActivityStarts(IIntentSender target,
-                IBinder whitelistToken, int flags) {
+                IBinder allowlistToken, int flags) {
             if (!(target instanceof PendingIntentRecord)) {
                 Slog.w(TAG, "setPendingIntentAllowBgActivityStarts():"
                         + " not a PendingIntentRecord: " + target);
                 return;
             }
             synchronized (ActivityManagerService.this) {
-                ((PendingIntentRecord) target).setAllowBgActivityStarts(whitelistToken, flags);
+                ((PendingIntentRecord) target).setAllowBgActivityStarts(allowlistToken, flags);
             }
         }
 
         @Override
         public void clearPendingIntentAllowBgActivityStarts(IIntentSender target,
-                IBinder whitelistToken) {
+                IBinder allowlistToken) {
             if (!(target instanceof PendingIntentRecord)) {
                 Slog.w(TAG, "clearPendingIntentAllowBgActivityStarts():"
                         + " not a PendingIntentRecord: " + target);
                 return;
             }
             synchronized (ActivityManagerService.this) {
-                ((PendingIntentRecord) target).clearAllowBgActivityStarts(whitelistToken);
+                ((PendingIntentRecord) target).clearAllowBgActivityStarts(allowlistToken);
             }
         }
 
         @Override
-        public void setDeviceIdleWhitelist(int[] allAppids, int[] exceptIdleAppids) {
+        public void setDeviceIdleAllowlist(int[] allAppids, int[] exceptIdleAppids) {
             synchronized (ActivityManagerService.this) {
                 synchronized (mProcLock) {
                     mDeviceIdleAllowlist = allAppids;
@@ -15152,14 +15168,16 @@
         }
 
         @Override
-        public void updateDeviceIdleTempWhitelist(int[] appids, int changingUid, boolean adding,
-                long durationMs, @TempAllowListType int type) {
+        public void updateDeviceIdleTempAllowlist(int[] appids, int changingUid, boolean adding,
+                long durationMs, @TempAllowListType int type, @ReasonCode int reasonCode,
+                @Nullable String reason, int callingUid) {
             synchronized (ActivityManagerService.this) {
                 synchronized (mProcLock) {
                     mDeviceIdleTempAllowlist = appids;
                     if (adding) {
-                        if (type == TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED) {
-                            mFgsStartTempAllowList.add(changingUid, durationMs);
+                        if (type == TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED) {
+                            mFgsStartTempAllowList.add(changingUid, durationMs, reasonCode, reason,
+                                    callingUid);
                         }
                     }
                     setAppIdTempAllowlistStateLSP(changingUid, adding);
@@ -15523,11 +15541,11 @@
         }
 
         @Override
-        public void tempWhitelistForPendingIntent(int callerPid, int callerUid, int targetUid,
-                long duration, int type, String tag) {
+        public void tempAllowlistForPendingIntent(int callerPid, int callerUid, int targetUid,
+                long duration, int type, @ReasonCode int reasonCode, String reason) {
             synchronized (ActivityManagerService.this) {
                 ActivityManagerService.this.tempAllowlistForPendingIntentLocked(
-                        callerPid, callerUid, targetUid, duration, type, tag);
+                        callerPid, callerUid, targetUid, duration, type, reasonCode, reason);
             }
         }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index c971bd2..5ad77a3 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -168,6 +168,7 @@
     private int mTaskId;
     private boolean mIsTaskOverlay;
     private boolean mIsLockTask;
+    private boolean mAsync;
     private BroadcastOptions mBroadcastOptions;
 
     final boolean mDumping;
@@ -342,6 +343,7 @@
         mTaskId = INVALID_TASK_ID;
         mIsTaskOverlay = false;
         mIsLockTask = false;
+        mAsync = false;
         mBroadcastOptions = null;
 
         return Intent.parseCommandArgs(this, new Intent.CommandOptionHandler() {
@@ -406,6 +408,8 @@
                         mBroadcastOptions = BroadcastOptions.makeBasic();
                     }
                     mBroadcastOptions.setBackgroundActivityStartsAllowed(true);
+                } else if (opt.equals("--async")) {
+                    mAsync = true;
                 } else {
                     return false;
                 }
@@ -756,7 +760,9 @@
         mInterface.broadcastIntentWithFeature(null, null, intent, null, receiver, 0, null, null,
                 requiredPermissions, android.app.AppOpsManager.OP_NONE, bundle, true, false,
                 mUserId);
-        receiver.waitForFinish();
+        if (!mAsync) {
+            receiver.waitForFinish();
+        }
         return 0;
     }
 
@@ -3180,13 +3186,17 @@
             pw.println("      Stop a Service.  Options are:");
             pw.println("      --user <USER_ID> | current: Specify which user to run as; if not");
             pw.println("          specified then run as the current user.");
-            pw.println("  broadcast [--user <USER_ID> | all | current] <INTENT>");
+            pw.println("  broadcast [--user <USER_ID> | all | current]");
+            pw.println("          [--receiver-permission <PERMISSION>]");
+            pw.println("          [--allow-background-activity-starts]");
+            pw.println("          [--async] <INTENT>");
             pw.println("      Send a broadcast Intent.  Options are:");
             pw.println("      --user <USER_ID> | all | current: Specify which user to send to; if not");
             pw.println("          specified then send to all users.");
             pw.println("      --receiver-permission <PERMISSION>: Require receiver to hold permission.");
             pw.println("      --allow-background-activity-starts: The receiver may start activities");
             pw.println("          even if in the background.");
+            pw.println("      --async: Send without waiting for the completion of the receiver.");
             pw.println("  instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]");
             pw.println("          [--user <USER_ID> | current]");
             pw.println("          [--no-hidden-api-checks [--no-test-api-access]]");
diff --git a/services/core/java/com/android/server/am/AppErrorDialog.java b/services/core/java/com/android/server/am/AppErrorDialog.java
index 48222cb..a9e5571 100644
--- a/services/core/java/com/android/server/am/AppErrorDialog.java
+++ b/services/core/java/com/android/server/am/AppErrorDialog.java
@@ -18,10 +18,7 @@
 
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.res.Resources;
 import android.os.Build;
 import android.os.Bundle;
@@ -138,19 +135,6 @@
         findViewById(com.android.internal.R.id.customPanel).setVisibility(View.VISIBLE);
     }
 
-    @Override
-    public void onStart() {
-        super.onStart();
-        getContext().registerReceiver(mReceiver,
-                new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
-    }
-
-    @Override
-    protected void onStop() {
-        super.onStop();
-        getContext().unregisterReceiver(mReceiver);
-    }
-
     private final Handler mHandler = new Handler() {
         public void handleMessage(Message msg) {
             setResult(msg.what);
@@ -204,15 +188,6 @@
         }
     }
 
-    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
-                cancel();
-            }
-        }
-    };
-
     static class Data {
         AppErrorResult result;
         int taskId;
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index e5a5cff..3602f44 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -29,6 +29,7 @@
 
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
+import android.app.AnrController;
 import android.app.ApplicationErrorReport;
 import android.app.ApplicationExitInfo;
 import android.content.ActivityNotFoundException;
@@ -1058,7 +1059,26 @@
                     Settings.Secure.ANR_SHOW_BACKGROUND, 0,
                     mService.mUserController.getCurrentUserId()) != 0;
             if (mService.mAtmInternal.canShowErrorDialogs() || showBackground) {
-                errState.getDialogController().showAnrDialogs(data);
+                AnrController anrController = errState.getDialogController().getAnrController();
+                if (anrController == null) {
+                    errState.getDialogController().showAnrDialogs(data);
+                } else {
+                    String packageName = proc.info.packageName;
+                    int uid = proc.info.uid;
+                    boolean showDialog = anrController.onAnrDelayCompleted(packageName, uid);
+
+                    if (showDialog) {
+                        Slog.d(TAG, "ANR delay completed. Showing ANR dialog for package: "
+                                + packageName);
+                        errState.getDialogController().showAnrDialogs(data);
+                    } else {
+                        Slog.d(TAG, "ANR delay completed. Cancelling ANR dialog for package: "
+                                + packageName);
+                        errState.setNotResponding(false);
+                        errState.setNotRespondingReport(null);
+                        errState.getDialogController().clearAnrDialogs();
+                    }
+                }
             } else {
                 MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
                         AppNotRespondingDialog.CANT_SHOW);
diff --git a/services/core/java/com/android/server/am/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
index 77d2898..b233a2c 100644
--- a/services/core/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
@@ -181,6 +181,11 @@
         }
     };
 
+    @Override
+    protected void closeDialog() {
+        mHandler.obtainMessage(FORCE_CLOSE).sendToTarget();
+    }
+
     static class Data {
         final ProcessRecord proc;
         final ApplicationInfo aInfo;
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index c8630fa..f8494d8 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -1327,6 +1327,8 @@
         // Get a list of Stats that have vsize > 0
         final List<ProcessCpuTracker.Stats> stats = getCpuStats(st -> st.vsize > 0);
         final int statsCount = stats.size();
+        long totalMemtrackGraphics = 0;
+        long totalMemtrackGl = 0;
         for (int i = 0; i < statsCount; i++) {
             ProcessCpuTracker.Stats st = stats.get(i);
             long pss = Debug.getPss(st.pid, swaptrackTmp, memtrackTmp);
@@ -1337,6 +1339,8 @@
                     mi.pss = pss;
                     mi.swapPss = swaptrackTmp[1];
                     mi.memtrack = memtrackTmp[0];
+                    totalMemtrackGraphics += memtrackTmp[1];
+                    totalMemtrackGl += memtrackTmp[2];
                     memInfos.add(mi);
                 }
             }
@@ -1345,20 +1349,18 @@
         long totalPss = 0;
         long totalSwapPss = 0;
         long totalMemtrack = 0;
-        long totalMemtrackGraphics = 0;
-        long totalMemtrackGl = 0;
         for (int i = 0, size = memInfos.size(); i < size; i++) {
             ProcessMemInfo mi = memInfos.get(i);
             if (mi.pss == 0) {
                 mi.pss = Debug.getPss(mi.pid, swaptrackTmp, memtrackTmp);
                 mi.swapPss = swaptrackTmp[1];
                 mi.memtrack = memtrackTmp[0];
+                totalMemtrackGraphics += memtrackTmp[1];
+                totalMemtrackGl += memtrackTmp[2];
             }
             totalPss += mi.pss;
             totalSwapPss += mi.swapPss;
             totalMemtrack += mi.memtrack;
-            totalMemtrackGraphics += memtrackTmp[1];
-            totalMemtrackGl += memtrackTmp[2];
         }
         Collections.sort(memInfos, new Comparator<ProcessMemInfo>() {
             @Override public int compare(ProcessMemInfo lhs, ProcessMemInfo rhs) {
diff --git a/services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java b/services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java
index 3ce2471..262e795 100644
--- a/services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java
+++ b/services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java
@@ -61,6 +61,11 @@
     public void onStop() {
     }
 
+    @Override
+    protected void closeDialog() {
+        /* Do nothing */
+    }
+
     private final Handler mHandler = new Handler() {
         public void handleMessage(Message msg) {
             switch (msg.what) {
diff --git a/services/core/java/com/android/server/am/BaseErrorDialog.java b/services/core/java/com/android/server/am/BaseErrorDialog.java
index aabb587..7b5f2cd 100644
--- a/services/core/java/com/android/server/am/BaseErrorDialog.java
+++ b/services/core/java/com/android/server/am/BaseErrorDialog.java
@@ -16,16 +16,19 @@
 
 package com.android.server.am;
 
-import com.android.internal.R;
-
 import android.app.AlertDialog;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.os.Handler;
 import android.os.Message;
 import android.view.KeyEvent;
 import android.view.WindowManager;
 import android.widget.Button;
 
+import com.android.internal.R;
+
 public class BaseErrorDialog extends AlertDialog {
     private static final int ENABLE_BUTTONS = 0;
     private static final int DISABLE_BUTTONS = 1;
@@ -44,10 +47,19 @@
         getWindow().setAttributes(attrs);
     }
 
+    @Override
     public void onStart() {
         super.onStart();
         mHandler.sendEmptyMessage(DISABLE_BUTTONS);
         mHandler.sendMessageDelayed(mHandler.obtainMessage(ENABLE_BUTTONS), 1000);
+        getContext().registerReceiver(mReceiver,
+                new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        getContext().unregisterReceiver(mReceiver);
     }
 
     public boolean dispatchKeyEvent(KeyEvent event) {
@@ -84,4 +96,24 @@
             }
         }
     };
+
+    /**
+     * Called when received ACTION_CLOSE_SYSTEM_DIALOGS.
+     */
+    protected void closeDialog() {
+        if (mCancelable) {
+            cancel();
+        } else {
+            dismiss();
+        }
+    }
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
+                closeDialog();
+            }
+        }
+    };
 }
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 34ff774..2906193 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -22,6 +22,7 @@
 
 import static com.android.server.am.ActivityManagerDebugConfig.*;
 
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
@@ -43,6 +44,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.PowerWhitelistManager;
 import android.os.PowerWhitelistManager.TempAllowListType;
 import android.os.Process;
 import android.os.RemoteException;
@@ -903,8 +905,9 @@
         return false;
     }
 
-    final void scheduleTempWhitelistLocked(int uid, long duration, BroadcastRecord r,
-            @TempAllowListType int type) {
+    final void scheduleTempAllowlistLocked(int uid, long duration, BroadcastRecord r,
+            @TempAllowListType int type, @PowerWhitelistManager.ReasonCode int reasonCode,
+            @Nullable String reason) {
         if (duration > Integer.MAX_VALUE) {
             duration = Integer.MAX_VALUE;
         }
@@ -926,10 +929,11 @@
             b.append(r.intent.getData());
         }
         if (DEBUG_BROADCAST) {
-            Slog.v(TAG, "Broadcast temp whitelist uid=" + uid + " duration=" + duration
+            Slog.v(TAG, "Broadcast temp allowlist uid=" + uid + " duration=" + duration
                     + " type=" + type + " : " + b.toString());
         }
-        mService.tempAllowlistUidLocked(uid, duration, b.toString(), type);
+        mService.tempAllowlistUidLocked(uid, duration, reasonCode, b.toString(), type,
+                r.callingUid);
     }
 
     /**
@@ -1332,10 +1336,12 @@
                     // 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.getTemporaryAppWhitelistDuration() > 0) {
-                    scheduleTempWhitelistLocked(filter.owningUid,
-                            brOptions.getTemporaryAppWhitelistDuration(), r,
-                            brOptions.getTemporaryAppWhitelistType());
+                if (brOptions != null && brOptions.getTemporaryAppAllowlistDuration() > 0) {
+                    scheduleTempAllowlistLocked(filter.owningUid,
+                            brOptions.getTemporaryAppAllowlistDuration(), r,
+                            brOptions.getTemporaryAppAllowlistType(),
+                            brOptions.getTemporaryAppAllowlistReasonCode(),
+                            brOptions.getTemporaryAppAllowlistReason());
                 }
             }
             return;
@@ -1619,11 +1625,13 @@
         }
 
         final boolean isActivityCapable =
-                (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0);
+                (brOptions != null && brOptions.getTemporaryAppAllowlistDuration() > 0);
         if (isActivityCapable) {
-            scheduleTempWhitelistLocked(receiverUid,
-                    brOptions.getTemporaryAppWhitelistDuration(), r,
-                    brOptions.getTemporaryAppWhitelistType());
+            scheduleTempAllowlistLocked(receiverUid,
+                    brOptions.getTemporaryAppAllowlistDuration(), r,
+                    brOptions.getTemporaryAppAllowlistType(),
+                    brOptions.getTemporaryAppAllowlistReasonCode(),
+                    brOptions.getTemporaryAppAllowlistReason());
         }
 
         // Broadcast is being executed, its package can't be stopped.
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index a34163c..c5f082a 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -536,18 +536,6 @@
     }
 
     /**
-     * Enable or disable the freezer. When enable == false all frozen processes are unfrozen,
-     * but aren't removed from the freezer. While in this state, processes can be added or removed
-     * by using Process.setProcessFrozen(), but they wouldn't be actually frozen until the freezer
-     * is enabled. If enable == true all processes in the freezer are frozen.
-     *
-     * @param enable Specify whether to enable (true) or disable (false) the freezer.
-     *
-     * @hide
-     */
-    private static native void enableFreezerInternal(boolean enable);
-
-    /**
      * Informs binder that a process is about to be frozen. If freezer is enabled on a process via
      * this method, this method will synchronously dispatch all pending transactions to the
      * specified pid. This method will not add significant latencies when unfreezing.
@@ -590,10 +578,6 @@
 
             if (state == '1' || state == '0') {
                 supported = true;
-                // This is a workaround after reverting the cgroup v2 uid/pid hierarchy due to
-                // http://b/179006802.
-                // TODO: remove once the uid/pid hierarchy is restored
-                enableFreezerInternal(true);
             } else {
                 Slog.e(TAG_AM, "unexpected value in cgroup.freeze");
             }
diff --git a/services/core/java/com/android/server/am/ErrorDialogController.java b/services/core/java/com/android/server/am/ErrorDialogController.java
index ef135d5..f23d309 100644
--- a/services/core/java/com/android/server/am/ErrorDialogController.java
+++ b/services/core/java/com/android/server/am/ErrorDialogController.java
@@ -16,6 +16,8 @@
 
 package com.android.server.am;
 
+import android.annotation.Nullable;
+import android.app.AnrController;
 import android.app.Dialog;
 import android.content.Context;
 
@@ -57,6 +59,13 @@
     @GuardedBy("mProcLock")
     private AppWaitingForDebuggerDialog mWaitDialog;
 
+    /**
+     * ANR dialog controller
+     */
+    @GuardedBy("mProcLock")
+    @Nullable
+    private AnrController mAnrController;
+
     @GuardedBy("mProcLock")
     boolean hasCrashDialogs() {
         return mCrashDialogs != null;
@@ -118,6 +127,7 @@
         }
         forAllDialogs(mAnrDialogs, Dialog::dismiss);
         mAnrDialogs = null;
+        mAnrController = null;
     }
 
     @GuardedBy("mProcLock")
@@ -220,6 +230,17 @@
         });
     }
 
+    @GuardedBy("mProcLock")
+    @Nullable
+    AnrController getAnrController() {
+        return mAnrController;
+    }
+
+    @GuardedBy("mProcLock")
+    void setAnrController(AnrController controller) {
+        mAnrController = controller;
+    }
+
     /**
      * Helper function to collect contexts from crashed app located displays.
      *
diff --git a/services/core/java/com/android/server/am/FgsStartTempAllowList.java b/services/core/java/com/android/server/am/FgsStartTempAllowList.java
index 4d8749c..1f897b5 100644
--- a/services/core/java/com/android/server/am/FgsStartTempAllowList.java
+++ b/services/core/java/com/android/server/am/FgsStartTempAllowList.java
@@ -18,24 +18,53 @@
 
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 
+import android.annotation.Nullable;
+import android.os.PowerWhitelistManager.ReasonCode;
 import android.os.SystemClock;
 import android.util.Slog;
-import android.util.SparseLongArray;
+import android.util.SparseArray;
 
 /**
  * List of uids that are temporarily allowed to start FGS from background.
  */
 final class FgsStartTempAllowList {
     private static final int MAX_SIZE = 100;
+
+    public static final class TempFgsAllowListEntry {
+        final long mExpirationTime;
+        final long mDuration;
+        final @ReasonCode int mReasonCode;
+        final String mReason;
+        final int mCallingUid;
+
+        TempFgsAllowListEntry(long expirationTime, long duration, @ReasonCode int reasonCode,
+                String reason, int callingUid) {
+            mExpirationTime = expirationTime;
+            mDuration = duration;
+            mReasonCode = reasonCode;
+            mReason = reason;
+            mCallingUid = callingUid;
+        }
+    }
+
     /**
-     * The key is the uid, the value is expiration elapse time in ms of this temp-allowed uid.
+     * The key is the uid, the value is a TempAllowListEntry.
      */
-    private final SparseLongArray mTempAllowListFgs = new SparseLongArray();
+    private final SparseArray<TempFgsAllowListEntry> mTempAllowListFgs = new SparseArray<>();
 
     FgsStartTempAllowList() {
     }
 
-    void add(int uid, long duration) {
+    /**
+     * Add a uid and its duration with reason into the FGS temp-allowlist.
+     * @param uid
+     * @param duration temp-allowlisted duration in milliseconds.
+     * @param reason A human-readable reason for logging purposes.
+     * @param callingUid the callingUid that setup this temp allowlist, only valid when param adding
+     *                   is true.
+     */
+    void add(int uid, long duration, @ReasonCode int reasonCode, @Nullable String reason,
+            int callingUid) {
         if (duration <= 0) {
             Slog.e(TAG_AM, "FgsStartTempAllowList bad duration:" + duration + " uid: "
                     + uid);
@@ -48,26 +77,36 @@
         }
         final long now = SystemClock.elapsedRealtime();
         for (int index = mTempAllowListFgs.size() - 1; index >= 0; index--) {
-            if (mTempAllowListFgs.valueAt(index) < now) {
+            if (mTempAllowListFgs.valueAt(index).mExpirationTime < now) {
                 mTempAllowListFgs.removeAt(index);
             }
         }
-        final long existingExpirationTime = mTempAllowListFgs.get(uid, -1);
+        final TempFgsAllowListEntry existing = mTempAllowListFgs.get(uid);
         final long expirationTime = now + duration;
-        if (existingExpirationTime == -1 || existingExpirationTime < expirationTime) {
-            mTempAllowListFgs.put(uid, expirationTime);
+        if (existing == null || existing.mExpirationTime < expirationTime) {
+            mTempAllowListFgs.put(uid,
+                    new TempFgsAllowListEntry(expirationTime, duration, reasonCode,
+                            reason == null ? "" : reason, callingUid));
         }
     }
 
-    boolean isAllowed(int uid) {
+    /**
+     * Is this uid temp-allowlisted to start FGS.
+     * @param uid
+     * @return If uid is in the temp-allowlist, return the {@link TempFgsAllowListEntry}; If not in
+     *         temp-allowlist, return null.
+     */
+    @Nullable
+    TempFgsAllowListEntry getAllowedDurationAndReason(int uid) {
         final int index = mTempAllowListFgs.indexOfKey(uid);
         if (index < 0) {
-            return false;
-        } else if (mTempAllowListFgs.valueAt(index) < SystemClock.elapsedRealtime()) {
+            return null;
+        } else if (mTempAllowListFgs.valueAt(index).mExpirationTime
+                < SystemClock.elapsedRealtime()) {
             mTempAllowListFgs.removeAt(index);
-            return false;
+            return null;
         } else {
-            return true;
+            return mTempAllowListFgs.valueAt(index);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 87cba54..06e879b 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -21,6 +21,7 @@
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_NETWORK;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
 import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
 import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
@@ -41,6 +42,7 @@
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
+import static android.os.PowerWhitelistManager.REASON_DENIED;
 import static android.os.Process.SCHED_OTHER;
 import static android.os.Process.THREAD_GROUP_BACKGROUND;
 import static android.os.Process.THREAD_GROUP_DEFAULT;
@@ -51,7 +53,6 @@
 import static android.os.Process.setThreadPriority;
 import static android.os.Process.setThreadScheduler;
 
-import static com.android.server.am.ActiveServices.FGS_FEATURE_DENIED;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKUP;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU;
@@ -521,8 +522,6 @@
 
         computeOomAdjLSP(app, cachedAdj, TOP_APP, doingAll, now, false, true);
 
-        boolean success = applyOomAdjLSP(app, doingAll, now, SystemClock.elapsedRealtime());
-
         if (uidRec != null) {
             // After uidRec.reset() above, for UidRecord with multiple processes (ProcessRecord),
             // we need to apply all ProcessRecord into UidRecord.
@@ -539,7 +538,7 @@
             }
         }
 
-        return success;
+        return applyOomAdjLSP(app, doingAll, now, SystemClock.elapsedRealtime());
     }
 
     /**
@@ -1967,7 +1966,7 @@
                     int clientProcState = cstate.getCurRawProcState();
 
                     // pass client's mAllowStartFgs to the app if client is not persistent process.
-                    if (cstate.getAllowedStartFgs() != FGS_FEATURE_DENIED
+                    if (cstate.getAllowedStartFgs() != REASON_DENIED
                             && cstate.getMaxAdj() >= ProcessList.FOREGROUND_APP_ADJ) {
                         state.setAllowStartFgs(cstate.getAllowedStartFgs());
                     }
@@ -1981,6 +1980,21 @@
                             capability |= cstate.getCurCapability();
                         }
 
+                        // If an app has network capability by default
+                        // (by having procstate <= BFGS), then the apps it binds to will get
+                        // elevated to a high enough procstate anyway to get network unless they
+                        // request otherwise, so don't propagate the network capability by default
+                        // in this case unless they explicitly request it.
+                        if ((cstate.getCurCapability() & PROCESS_CAPABILITY_NETWORK) != 0) {
+                            if (clientProcState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
+                                if ((cr.flags & Context.BIND_ALLOW_NETWORK_ACCESS) != 0) {
+                                    capability |= PROCESS_CAPABILITY_NETWORK;
+                                }
+                            } else {
+                                capability |= PROCESS_CAPABILITY_NETWORK;
+                            }
+                        }
+
                         if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
                             // If the other app is cached for any reason, for purposes here
                             // we are going to consider it empty.  The specific cached state
@@ -2048,6 +2062,10 @@
                                         && clientAdj <= ProcessList.PERCEPTIBLE_APP_ADJ
                                         && adj >= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
                                     newAdj = ProcessList.PERCEPTIBLE_LOW_APP_ADJ;
+                                } else if ((cr.flags & Context.BIND_ALMOST_PERCEPTIBLE) != 0
+                                        && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
+                                        && adj >= ProcessList.PERCEPTIBLE_MEDIUM_APP_ADJ) {
+                                    newAdj = ProcessList.PERCEPTIBLE_MEDIUM_APP_ADJ;
                                 } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0
                                         && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
                                         && adj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
@@ -2117,13 +2135,13 @@
                                 if (enabled) {
                                     if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
                                         // TOP process passes all capabilities to the service.
-                                        capability |= PROCESS_CAPABILITY_ALL;
+                                        capability |= cstate.getCurCapability();
                                     } else {
                                         // TOP process passes no capability to the service.
                                     }
                                 } else {
                                     // TOP process passes all capabilities to the service.
-                                    capability |= PROCESS_CAPABILITY_ALL;
+                                    capability |= cstate.getCurCapability();
                                 }
                             }
                         } else if ((cr.flags & Context.BIND_IMPORTANT_BACKGROUND) == 0) {
@@ -2448,20 +2466,20 @@
             case PROCESS_STATE_TOP:
                 return PROCESS_CAPABILITY_ALL;
             case PROCESS_STATE_BOUND_TOP:
-                return PROCESS_CAPABILITY_NONE;
+                return PROCESS_CAPABILITY_NETWORK;
             case PROCESS_STATE_FOREGROUND_SERVICE:
                 if (psr.hasForegroundServices()) {
                     // Capability from FGS are conditional depending on foreground service type in
                     // manifest file and the mAllowWhileInUsePermissionInFgs flag.
-                    return PROCESS_CAPABILITY_NONE;
+                    return PROCESS_CAPABILITY_NETWORK;
                 } else {
                     // process has no FGS, the PROCESS_STATE_FOREGROUND_SERVICE is from client.
                     // the implicit capability could be removed in the future, client should use
                     // BIND_INCLUDE_CAPABILITY flag.
-                    return PROCESS_CAPABILITY_ALL_IMPLICIT;
+                    return PROCESS_CAPABILITY_ALL_IMPLICIT | PROCESS_CAPABILITY_NETWORK;
                 }
             case PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
-                return PROCESS_CAPABILITY_NONE;
+                return PROCESS_CAPABILITY_NETWORK;
             default:
                 return PROCESS_CAPABILITY_NONE;
         }
diff --git a/services/core/java/com/android/server/am/PendingIntentController.java b/services/core/java/com/android/server/am/PendingIntentController.java
index 42172bf..534bd84 100644
--- a/services/core/java/com/android/server/am/PendingIntentController.java
+++ b/services/core/java/com/android/server/am/PendingIntentController.java
@@ -36,6 +36,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.PowerWhitelistManager;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -300,15 +301,16 @@
         }
     }
 
-    void setPendingIntentWhitelistDuration(IIntentSender target, IBinder whitelistToken,
-            long duration, int type) {
+    void setPendingIntentAllowlistDuration(IIntentSender target, IBinder allowlistToken,
+            long duration, int type, @PowerWhitelistManager.ReasonCode int reasonCode,
+            @Nullable String reason) {
         if (!(target instanceof PendingIntentRecord)) {
             Slog.w(TAG, "markAsSentFromNotification(): not a PendingIntentRecord: " + target);
             return;
         }
         synchronized (mLock) {
-            ((PendingIntentRecord) target).setWhitelistDurationLocked(whitelistToken, duration,
-                    type);
+            ((PendingIntentRecord) target).setAllowlistDurationLocked(allowlistToken, duration,
+                    type, reasonCode, reason);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 0eb48f6..51666ac 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -31,13 +31,14 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.PowerWhitelistManager;
+import android.os.PowerWhitelistManager.ReasonCode;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.TransactionTooLargeException;
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.Pair;
 import android.util.Slog;
 import android.util.TimeUtils;
 
@@ -67,7 +68,7 @@
      * milliseconds, Integer is allowlist type defined at
      * {@link android.os.PowerWhitelistManager.TempAllowListType}
      */
-    private ArrayMap<IBinder, Pair<Long, Integer>> mWhitelistDuration;
+    private ArrayMap<IBinder, TempAllowListDuration> mAllowlistDuration;
     private RemoteCallbackList<IResultReceiver> mCancelCallbacks;
     private ArraySet<IBinder> mAllowBgActivityStartsForActivitySender = new ArraySet<>();
     private ArraySet<IBinder> mAllowBgActivityStartsForBroadcastSender = new ArraySet<>();
@@ -214,6 +215,21 @@
         }
     }
 
+    static final class TempAllowListDuration {
+        long duration;
+        int type;
+        @ReasonCode int reasonCode;
+        @Nullable String reason;
+
+        TempAllowListDuration(long _duration, int _type, @ReasonCode int _reasonCode,
+                String _reason) {
+            duration = _duration;
+            type = _type;
+            reasonCode = _reasonCode;
+            reason = _reason;
+        }
+    }
+
     PendingIntentRecord(PendingIntentController _controller, Key _k, int _u) {
         controller = _controller;
         key = _k;
@@ -221,18 +237,19 @@
         ref = new WeakReference<>(this);
     }
 
-    void setWhitelistDurationLocked(IBinder whitelistToken, long duration, int type) {
+    void setAllowlistDurationLocked(IBinder allowlistToken, long duration, int type,
+            @ReasonCode int reasonCode, @Nullable String reason) {
         if (duration > 0) {
-            if (mWhitelistDuration == null) {
-                mWhitelistDuration = new ArrayMap<>();
+            if (mAllowlistDuration == null) {
+                mAllowlistDuration = new ArrayMap<>();
             }
-            mWhitelistDuration.put(whitelistToken, new Pair(duration, type));
-        } else if (mWhitelistDuration != null) {
-            mWhitelistDuration.remove(whitelistToken);
-            if (mWhitelistDuration.size() <= 0) {
-                mWhitelistDuration = null;
+            mAllowlistDuration.put(allowlistToken,
+                    new TempAllowListDuration(duration, type, reasonCode, reason));
+        } else if (mAllowlistDuration != null) {
+            mAllowlistDuration.remove(allowlistToken);
+            if (mAllowlistDuration.size() <= 0) {
+                mAllowlistDuration = null;
             }
-
         }
         this.stringName = null;
     }
@@ -280,25 +297,25 @@
         return listeners;
     }
 
-    public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
+    public void send(int code, Intent intent, String resolvedType, IBinder allowlistToken,
             IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
-        sendInner(code, intent, resolvedType, whitelistToken, finishedReceiver,
+        sendInner(code, intent, resolvedType, allowlistToken, finishedReceiver,
                 requiredPermission, null, null, 0, 0, 0, options);
     }
 
-    public int sendWithResult(int code, Intent intent, String resolvedType, IBinder whitelistToken,
+    public int sendWithResult(int code, Intent intent, String resolvedType, IBinder allowlistToken,
             IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
-        return sendInner(code, intent, resolvedType, whitelistToken, finishedReceiver,
+        return sendInner(code, intent, resolvedType, allowlistToken, finishedReceiver,
                 requiredPermission, null, null, 0, 0, 0, options);
     }
 
-    public int sendInner(int code, Intent intent, String resolvedType, IBinder whitelistToken,
+    public int sendInner(int code, Intent intent, String resolvedType, IBinder allowlistToken,
             IIntentReceiver finishedReceiver, String requiredPermission, IBinder resultTo,
             String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle options) {
         if (intent != null) intent.setDefusable(true);
         if (options != null) options.setDefusable(true);
 
-        Pair<Long, Integer> duration = null;
+        TempAllowListDuration duration = null;
         Intent finalIntent = null;
         Intent[] allIntents = null;
         String[] allResolvedTypes = null;
@@ -347,8 +364,8 @@
                 mergedOptions.setCallerOptions(opts);
             }
 
-            if (mWhitelistDuration != null) {
-                duration = mWhitelistDuration.get(whitelistToken);
+            if (mAllowlistDuration != null) {
+                duration = mAllowlistDuration.get(allowlistToken);
             }
 
             if (key.type == ActivityManager.INTENT_SENDER_ACTIVITY
@@ -377,7 +394,9 @@
         try {
             if (duration != null) {
                 StringBuilder tag = new StringBuilder(64);
-                tag.append("pendingintent:");
+                tag.append("setPendingIntentAllowlistDuration,reason:");
+                tag.append(duration.reason == null ? "" : duration.reason);
+                tag.append(",pendingintent:");
                 UserHandle.formatUid(tag, callingUid);
                 tag.append(":");
                 if (finalIntent.getAction() != null) {
@@ -387,8 +406,8 @@
                 } else if (finalIntent.getData() != null) {
                     tag.append(finalIntent.getData().toSafeString());
                 }
-                controller.mAmInternal.tempWhitelistForPendingIntent(callingPid, callingUid,
-                        uid, duration.first, duration.second, tag.toString());
+                controller.mAmInternal.tempAllowlistForPendingIntent(callingPid, callingUid,
+                        uid, duration.duration, duration.type, duration.reasonCode, tag.toString());
             }
 
             boolean sendFinish = finishedReceiver != null;
@@ -417,7 +436,8 @@
                                     allIntents, allResolvedTypes, resultTo, mergedOptions, userId,
                                     false /* validateIncomingUser */,
                                     this /* originatingPendingIntent */,
-                                    mAllowBgActivityStartsForActivitySender.contains(whitelistToken));
+                                    mAllowBgActivityStartsForActivitySender.contains(
+                                            allowlistToken));
                         } else {
                             res = controller.mAtmInternal.startActivityInPackage(uid, callingPid,
                                     callingUid, key.packageName, key.featureId, finalIntent,
@@ -426,7 +446,7 @@
                                     false /* validateIncomingUser */,
                                     this /* originatingPendingIntent */,
                                     mAllowBgActivityStartsForActivitySender.contains(
-                                            whitelistToken));
+                                            allowlistToken));
                         }
                     } catch (RuntimeException e) {
                         Slog.w(TAG, "Unable to send startActivity intent", e);
@@ -439,8 +459,8 @@
                 case ActivityManager.INTENT_SENDER_BROADCAST:
                     try {
                         final boolean allowedByToken =
-                                mAllowBgActivityStartsForBroadcastSender.contains(whitelistToken);
-                        final IBinder bgStartsToken = (allowedByToken) ? whitelistToken : null;
+                                mAllowBgActivityStartsForBroadcastSender.contains(allowlistToken);
+                        final IBinder bgStartsToken = (allowedByToken) ? allowlistToken : null;
 
                         // If a completion callback has been requested, require
                         // that the broadcast be delivered synchronously
@@ -460,8 +480,8 @@
                 case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE:
                     try {
                         final boolean allowedByToken =
-                                mAllowBgActivityStartsForServiceSender.contains(whitelistToken);
-                        final IBinder bgStartsToken = (allowedByToken) ? whitelistToken : null;
+                                mAllowBgActivityStartsForServiceSender.contains(allowlistToken);
+                        final IBinder bgStartsToken = (allowedByToken) ? allowlistToken : null;
 
                         controller.mAmInternal.startServiceInPackage(uid, finalIntent, resolvedType,
                                 key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE,
@@ -533,18 +553,23 @@
             pw.print(prefix); pw.print("sent="); pw.print(sent);
                     pw.print(" canceled="); pw.println(canceled);
         }
-        if (mWhitelistDuration != null) {
+        if (mAllowlistDuration != null) {
             pw.print(prefix);
-            pw.print("whitelistDuration=");
-            for (int i = 0; i < mWhitelistDuration.size(); i++) {
+            pw.print("allowlistDuration=");
+            for (int i = 0; i < mAllowlistDuration.size(); i++) {
                 if (i != 0) {
                     pw.print(", ");
                 }
-                pw.print(Integer.toHexString(System.identityHashCode(mWhitelistDuration.keyAt(i))));
+                TempAllowListDuration entry = mAllowlistDuration.valueAt(i);
+                pw.print(Integer.toHexString(System.identityHashCode(mAllowlistDuration.keyAt(i))));
                 pw.print(":");
-                TimeUtils.formatDuration(mWhitelistDuration.valueAt(i).first, pw);
+                TimeUtils.formatDuration(entry.duration, pw);
                 pw.print("/");
-                pw.print(mWhitelistDuration.valueAt(i).second);
+                pw.print(entry.type);
+                pw.print("/");
+                pw.print(PowerWhitelistManager.reasonCodeToString(entry.reasonCode));
+                pw.print("/");
+                pw.print(entry.reason);
             }
             pw.println();
         }
@@ -572,18 +597,23 @@
         }
         sb.append(' ');
         sb.append(key.typeName());
-        if (mWhitelistDuration != null) {
-            sb.append( " (whitelist: ");
-            for (int i = 0; i < mWhitelistDuration.size(); i++) {
+        if (mAllowlistDuration != null) {
+            sb.append(" (allowlist: ");
+            for (int i = 0; i < mAllowlistDuration.size(); i++) {
                 if (i != 0) {
                     sb.append(",");
                 }
+                TempAllowListDuration entry = mAllowlistDuration.valueAt(i);
                 sb.append(Integer.toHexString(System.identityHashCode(
-                        mWhitelistDuration.keyAt(i))));
+                        mAllowlistDuration.keyAt(i))));
                 sb.append(":");
-                TimeUtils.formatDuration(mWhitelistDuration.valueAt(i).first, sb);
+                TimeUtils.formatDuration(entry.duration, sb);
                 sb.append("/");
-                sb.append(mWhitelistDuration.valueAt(i).second);
+                sb.append(entry.type);
+                sb.append("/");
+                sb.append(PowerWhitelistManager.reasonCodeToString(entry.reasonCode));
+                sb.append("/");
+                sb.append(entry.reason);
             }
             sb.append(")");
         }
diff --git a/services/core/java/com/android/server/am/PreBootBroadcaster.java b/services/core/java/com/android/server/am/PreBootBroadcaster.java
index 60b2467..984fe40 100644
--- a/services/core/java/com/android/server/am/PreBootBroadcaster.java
+++ b/services/core/java/com/android/server/am/PreBootBroadcaster.java
@@ -17,6 +17,8 @@
 package com.android.server.am;
 
 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
+import static android.os.PowerWhitelistManager.REASON_PRE_BOOT_COMPLETED;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
 
 import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
@@ -117,9 +119,9 @@
             duration = amInternal.getBootTimeTempAllowListDuration();
         }
         final BroadcastOptions bOptions = BroadcastOptions.makeBasic();
-        bOptions.setTemporaryAppWhitelistDuration(
-                BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
-                duration);
+        bOptions.setTemporaryAppAllowlist(duration,
+                TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                REASON_PRE_BOOT_COMPLETED, "");
         synchronized (mService) {
             mService.broadcastIntentLocked(null, null, null, mIntent, null, this, 0, null, null,
                     null, AppOpsManager.OP_NONE, bOptions.toBundle(), true,
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index 1653123..3258f8a 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -22,6 +22,7 @@
 import static com.android.server.am.ProcessRecord.TAG;
 
 import android.app.ActivityManager;
+import android.app.AnrController;
 import android.app.ApplicationErrorReport;
 import android.app.ApplicationExitInfo;
 import android.content.ComponentName;
@@ -418,10 +419,16 @@
 
         // Retrieve max ANR delay from AnrControllers without the mService lock since the
         // controllers might in turn call into apps
-        long anrDialogDelayMs = mService.mActivityTaskManager.getMaxAnrDelayMillis(aInfo);
-        if (aInfo != null && aInfo.packageName != null && anrDialogDelayMs > 0) {
-            Slog.i(TAG, "Delaying ANR dialog for " + aInfo.packageName + " for " + anrDialogDelayMs
-                    + "ms");
+        AnrController anrController = mService.mActivityTaskManager.getAnrController(aInfo);
+        long anrDialogDelayMs = 0;
+        if (anrController != null) {
+            String packageName = aInfo.packageName;
+            int uid = aInfo.uid;
+            anrDialogDelayMs = anrController.getAnrDelayMillis(packageName, uid);
+            // Might execute an async binder call to a system app to show an interim
+            // ANR progress UI
+            anrController.onAnrDelayStarted(packageName, uid);
+            Slog.i(TAG, "ANR delay of " + anrDialogDelayMs + "ms started for " + packageName);
         }
 
         synchronized (mService) {
@@ -440,6 +447,7 @@
                 // Set the app's notResponding state, and look up the errorReportReceiver
                 makeAppNotRespondingLSP(activityShortComponentName,
                         annotation != null ? "ANR " + annotation : "ANR", info.toString());
+                mDialogController.setAnrController(anrController);
             }
 
             // Notify package manager service to possibly update package state
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index cb07a06..38330fe 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
 import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
 import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
 import static android.app.ActivityThread.PROC_START_SEQ_IDENT;
@@ -57,6 +58,7 @@
 
 import android.annotation.NonNull;
 import android.app.ActivityManager;
+import android.app.ActivityManager.ProcessCapability;
 import android.app.ActivityThread;
 import android.app.AppGlobals;
 import android.app.AppProtoEnums;
@@ -228,6 +230,11 @@
     // not so perceptible that it affects the user immediately if killed.
     static final int PERCEPTIBLE_LOW_APP_ADJ = 250;
 
+    // This is a process hosting services that are not perceptible to the user but the
+    // client (system) binding to it requested to treat it as if it is perceptible and avoid killing
+    // it if possible.
+    static final int PERCEPTIBLE_MEDIUM_APP_ADJ = 225;
+
     // This is a process only hosting components that are perceptible to the
     // user, and we really want to avoid killing them, but they are not
     // immediately visible. An example is background music playback.
@@ -1027,6 +1034,9 @@
         } else if (setAdj >= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
             return buildOomTag("prcl  ", "prcl", null, setAdj,
                     ProcessList.PERCEPTIBLE_LOW_APP_ADJ, compact);
+        } else if (setAdj >= ProcessList.PERCEPTIBLE_MEDIUM_APP_ADJ) {
+            return buildOomTag("prcm  ", "prcm", null, setAdj,
+                    ProcessList.PERCEPTIBLE_MEDIUM_APP_ADJ, compact);
         } else if (setAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
             return buildOomTag("prcp  ", "prcp", null, setAdj,
                     ProcessList.PERCEPTIBLE_APP_ADJ, compact);
@@ -4395,6 +4405,7 @@
             printOomLevel(pw, "FOREGROUND_APP_ADJ", FOREGROUND_APP_ADJ);
             printOomLevel(pw, "VISIBLE_APP_ADJ", VISIBLE_APP_ADJ);
             printOomLevel(pw, "PERCEPTIBLE_APP_ADJ", PERCEPTIBLE_APP_ADJ);
+            printOomLevel(pw, "PERCEPTIBLE_MEDIUM_APP_ADJ", PERCEPTIBLE_MEDIUM_APP_ADJ);
             printOomLevel(pw, "PERCEPTIBLE_LOW_APP_ADJ", PERCEPTIBLE_LOW_APP_ADJ);
             printOomLevel(pw, "BACKUP_APP_ADJ", BACKUP_APP_ADJ);
             printOomLevel(pw, "HEAVY_WEIGHT_APP_ADJ", HEAVY_WEIGHT_APP_ADJ);
@@ -4658,13 +4669,26 @@
         }
     }
 
-    /** Returns the uid's process state or PROCESS_STATE_NONEXISTENT if not running */
+    /**
+     * Returns the uid's process state or {@link ActivityManager#PROCESS_STATE_NONEXISTENT}
+     * if not running
+     */
     @GuardedBy(anyOf = {"mService", "mProcLock"})
     int getUidProcStateLOSP(int uid) {
         UidRecord uidRec = mActiveUids.get(uid);
         return uidRec == null ? PROCESS_STATE_NONEXISTENT : uidRec.getCurProcState();
     }
 
+    /**
+     * Returns the uid's process capability or {@link ActivityManager#PROCESS_CAPABILITY_NONE}
+     * if not running
+     */
+    @GuardedBy(anyOf = {"mService", "mProcLock"})
+    @ProcessCapability int getUidProcessCapabilityLOSP(int uid) {
+        UidRecord uidRec = mActiveUids.get(uid);
+        return uidRec == null ? PROCESS_CAPABILITY_NONE : uidRec.getCurCapability();
+    }
+
     /** Returns the UidRecord for the given uid, if it exists. */
     @GuardedBy(anyOf = {"mService", "mProcLock"})
     UidRecord getUidRecordLOSP(int uid) {
@@ -4749,8 +4773,9 @@
             if (!UserHandle.isApp(uidRec.getUid()) || !uidRec.hasInternetPermission) {
                 continue;
             }
-            // If process state is not changed, then there's nothing to do.
-            if (uidRec.getSetProcState() == uidRec.getCurProcState()) {
+            // If process state and capabilities are not changed, then there's nothing to do.
+            if (uidRec.getSetProcState() == uidRec.getCurProcState()
+                    && uidRec.getSetCapability() == uidRec.getCurCapability()) {
                 continue;
             }
             final int blockState = getBlockStateForUid(uidRec);
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index 499fbcb..6d783fc 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -23,22 +23,23 @@
 import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
 import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.PowerWhitelistManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
+import static android.os.PowerWhitelistManager.REASON_BACKGROUND_FGS_PERMISSION;
+import static android.os.PowerWhitelistManager.REASON_COMPANION_DEVICE_MANAGER;
+import static android.os.PowerWhitelistManager.REASON_DENIED;
+import static android.os.PowerWhitelistManager.REASON_DEVICE_OWNER;
+import static android.os.PowerWhitelistManager.REASON_PROFILE_OWNER;
+import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
+import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALLOW_LISTED;
+import static android.os.PowerWhitelistManager.REASON_SYSTEM_UID;
+import static android.os.PowerWhitelistManager.ReasonCode;
+import static android.os.PowerWhitelistManager.getReasonCodeFromProcState;
+import static android.os.PowerWhitelistManager.reasonCodeToString;
 import static android.os.Process.NFC_UID;
 import static android.os.Process.ROOT_UID;
 import static android.os.Process.SHELL_UID;
 import static android.os.Process.SYSTEM_UID;
 
-import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION;
-import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION;
-import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_COMPANION_APP;
-import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST;
-import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER;
-import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_PROC_STATE;
-import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_PROFILE_OWNER;
-import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION;
-import static com.android.server.am.ActiveServices.FGS_FEATURE_ALLOWED_BY_SYSTEM_UID;
-import static com.android.server.am.ActiveServices.FGS_FEATURE_DENIED;
-import static com.android.server.am.ActiveServices.fgsCodeToString;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
 import static com.android.server.am.ProcessRecord.TAG;
 
@@ -329,7 +330,7 @@
      * Does the process has permission to start FGS from background.
      */
     @GuardedBy("mService")
-    private @ActiveServices.FgsFeatureRetCode int mAllowStartFgsByPermission;
+    private @ReasonCode int mAllowStartFgsByPermission = REASON_DENIED;
 
     /**
      * Can this process start FGS from background?
@@ -337,7 +338,7 @@
      * another process through service binding.
      */
     @GuardedBy("mService")
-    private @ActiveServices.FgsFeatureRetCode int mAllowStartFgs;
+    private @ReasonCode int mAllowStartFgs = REASON_DENIED;
 
     /**
      * Debugging: primary thing impacting oom_adj.
@@ -1152,44 +1153,47 @@
     }
 
     @GuardedBy("mService")
+    int getAllowStartFgsState() {
+        return mAllowStartFgsState;
+    }
+
+    @GuardedBy("mService")
     boolean isAllowedStartFgsState() {
         return mAllowStartFgsState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
     }
 
     @GuardedBy("mService")
     void setAllowStartFgsByPermission() {
-        int ret = FGS_FEATURE_DENIED;
-        if (ret == FGS_FEATURE_DENIED) {
-            boolean isSystem = false;
-            final int uid = UserHandle.getAppId(mApp.info.uid);
-            switch (uid) {
-                case ROOT_UID:
-                case SYSTEM_UID:
-                case NFC_UID:
-                case SHELL_UID:
-                    isSystem = true;
-                    break;
-                default:
-                    isSystem = false;
-                    break;
-            }
-
-            if (isSystem) {
-                ret = FGS_FEATURE_ALLOWED_BY_SYSTEM_UID;
-            }
+        int ret = REASON_DENIED;
+        boolean isSystem = false;
+        final int uid = UserHandle.getAppId(mApp.info.uid);
+        switch (uid) {
+            case ROOT_UID:
+            case SYSTEM_UID:
+            case NFC_UID:
+            case SHELL_UID:
+                isSystem = true;
+                break;
+            default:
+                isSystem = false;
+                break;
         }
 
-        if (ret == FGS_FEATURE_DENIED) {
+        if (isSystem) {
+            ret = REASON_SYSTEM_UID;
+        }
+
+        if (ret == REASON_DENIED) {
             if (ActivityManager.checkComponentPermission(START_ACTIVITIES_FROM_BACKGROUND,
                     mApp.info.uid, -1, true) == PERMISSION_GRANTED) {
-                ret = FGS_FEATURE_ALLOWED_BY_BACKGROUND_ACTIVITY_PERMISSION;
+                ret = REASON_BACKGROUND_ACTIVITY_PERMISSION;
             } else if (ActivityManager.checkComponentPermission(
                     START_FOREGROUND_SERVICES_FROM_BACKGROUND,
                     mApp.info.uid, -1, true) == PERMISSION_GRANTED) {
-                ret = FGS_FEATURE_ALLOWED_BY_BACKGROUND_FGS_PERMISSION;
+                ret = REASON_BACKGROUND_FGS_PERMISSION;
             } else if (ActivityManager.checkComponentPermission(SYSTEM_ALERT_WINDOW,
                     mApp.info.uid, -1, true) == PERMISSION_GRANTED) {
-                ret = FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION;
+                ret = REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
             }
         }
         mAllowStartFgs = mAllowStartFgsByPermission = ret;
@@ -1197,59 +1201,65 @@
 
     @GuardedBy("mService")
     void setAllowStartFgs() {
-        if (mAllowStartFgs != FGS_FEATURE_DENIED) {
+        if (mAllowStartFgs != REASON_DENIED) {
             return;
         }
-        if (mAllowStartFgs == FGS_FEATURE_DENIED) {
+        if (mAllowStartFgs == REASON_DENIED) {
             if (isAllowedStartFgsState()) {
-                mAllowStartFgs = FGS_FEATURE_ALLOWED_BY_PROC_STATE;
+                mAllowStartFgs = getReasonCodeFromProcState(mAllowStartFgsState);
             }
         }
 
-        if (mAllowStartFgs == FGS_FEATURE_DENIED) {
+        if (mAllowStartFgs == REASON_DENIED) {
             // Is the calling UID a device owner app?
             if (mService.mInternal != null) {
                 if (mService.mInternal.isDeviceOwner(mApp.info.uid)) {
-                    mAllowStartFgs = FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER;
+                    mAllowStartFgs = REASON_DEVICE_OWNER;
                 }
             }
         }
 
-        if (mAllowStartFgs == FGS_FEATURE_DENIED) {
+        if (mAllowStartFgs == REASON_DENIED) {
             if (mService.mInternal != null) {
                 final boolean isCompanionApp = mService.mInternal.isAssociatedCompanionApp(
                         UserHandle.getUserId(mApp.info.uid), mApp.info.uid);
                 if (isCompanionApp) {
-                    mAllowStartFgs = FGS_FEATURE_ALLOWED_BY_COMPANION_APP;
+                    mAllowStartFgs = REASON_COMPANION_DEVICE_MANAGER;
                 }
             }
         }
 
-        if (mAllowStartFgs == FGS_FEATURE_DENIED) {
+        if (mAllowStartFgs == REASON_DENIED) {
             // Is the calling UID a profile owner app?
             if (mService.mInternal != null) {
                 if (mService.mInternal.isProfileOwner(mApp.info.uid)) {
-                    mAllowStartFgs = FGS_FEATURE_ALLOWED_BY_PROFILE_OWNER;
+                    mAllowStartFgs = REASON_PROFILE_OWNER;
                 }
             }
         }
 
-        if (mAllowStartFgs == FGS_FEATURE_DENIED) {
+        if (mAllowStartFgs == REASON_DENIED) {
             // uid is on DeviceIdleController's user/system allowlist
             // or AMS's FgsStartTempAllowList.
-            if (mService.isAllowlistedForFgsStartLOSP(mApp.info.uid)) {
-                mAllowStartFgs = FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST;
+            FgsStartTempAllowList.TempFgsAllowListEntry entry =
+                    mService.isAllowlistedForFgsStartLOSP(mApp.info.uid);
+            if (entry != null) {
+                if (entry == ActivityManagerService.FAKE_TEMP_ALLOWLIST_ENTRY) {
+                    mAllowStartFgs = REASON_SYSTEM_ALLOW_LISTED;
+                } else {
+                    mAllowStartFgs = entry.mReasonCode;
+                }
             }
         }
     }
 
     @GuardedBy("mService")
-    void setAllowStartFgs(@ActiveServices.FgsFeatureRetCode int allowStartFgs) {
+    void setAllowStartFgs(@ReasonCode int allowStartFgs) {
         mAllowStartFgs = allowStartFgs;
     }
 
     @GuardedBy("mService")
-    @ActiveServices.FgsFeatureRetCode int getAllowedStartFgs() {
+    @ReasonCode int getAllowedStartFgs() {
         return mAllowStartFgs;
     }
 
@@ -1291,9 +1301,9 @@
         pw.println();
         pw.print(prefix); pw.print("allowStartFgsState=");
         pw.println(mAllowStartFgsState);
-        if (mAllowStartFgs != FGS_FEATURE_DENIED) {
+        if (mAllowStartFgs != REASON_DENIED) {
             pw.print(prefix); pw.print("allowStartFgs=");
-            pw.println(fgsCodeToString(mAllowStartFgs));
+            pw.println(reasonCodeToString(mAllowStartFgs));
         }
         if (mHasShownUi || mApp.mProfile.hasPendingUiClean()) {
             pw.print(prefix); pw.print("hasShownUi="); pw.print(mHasShownUi);
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 485087d..3ab95d1 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -18,6 +18,7 @@
 
 import static android.app.PendingIntent.FLAG_IMMUTABLE;
 import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
+import static android.os.PowerWhitelistManager.REASON_DENIED;
 
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -36,6 +37,7 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.IBinder;
+import android.os.PowerWhitelistManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -101,7 +103,7 @@
     ProcessRecord isolatedProc; // keep track of isolated process, if requested
     ServiceState tracker; // tracking service execution, may be null
     ServiceState restartTracker; // tracking service restart
-    boolean whitelistManager; // any bindings to this service have BIND_ALLOW_WHITELIST_MANAGEMENT?
+    boolean allowlistManager; // any bindings to this service have BIND_ALLOW_WHITELIST_MANAGEMENT?
     boolean delayed;        // are we waiting to start this service in the background?
     boolean fgRequired;     // is the service required to go foreground after starting?
     boolean fgWaiting;      // is a timeout for going foreground already scheduled?
@@ -156,11 +158,14 @@
 
     // the most recent package that start/bind this service.
     String mRecentCallingPackage;
+    // the most recent uid that start/bind this service.
+    int mRecentCallingUid;
 
     // allow the service becomes foreground service? Service started from background may not be
     // allowed to become a foreground service.
-    @ActiveServices.FgsFeatureRetCode int mAllowStartForeground;
+    @PowerWhitelistManager.ReasonCode int mAllowStartForeground = REASON_DENIED;
     String mInfoAllowStartForeground;
+    FgsStartTempAllowList.TempFgsAllowListEntry mInfoTempFgsAllowListReason;
     boolean mLoggedInfoAllowStartForeground;
 
     String stringName;      // caching of toString
@@ -309,7 +314,7 @@
         if (isolatedProc != null) {
             isolatedProc.dumpDebug(proto, ServiceRecordProto.ISOLATED_PROC);
         }
-        proto.write(ServiceRecordProto.WHITELIST_MANAGER, whitelistManager);
+        proto.write(ServiceRecordProto.WHITELIST_MANAGER, allowlistManager);
         proto.write(ServiceRecordProto.DELAYED, delayed);
         if (isForeground || foregroundId != 0) {
             long fgToken = proto.start(ServiceRecordProto.FOREGROUND);
@@ -410,8 +415,8 @@
         if (isolatedProc != null) {
             pw.print(prefix); pw.print("isolatedProc="); pw.println(isolatedProc);
         }
-        if (whitelistManager) {
-            pw.print(prefix); pw.print("whitelistManager="); pw.println(whitelistManager);
+        if (allowlistManager) {
+            pw.print(prefix); pw.print("allowlistManager="); pw.println(allowlistManager);
         }
         if (mIsAllowedBgActivityStartsByBinding) {
             pw.print(prefix); pw.print("mIsAllowedBgActivityStartsByBinding=");
@@ -429,6 +434,8 @@
                 pw.println(mAllowWhileInUsePermissionInFgs);
         pw.print(prefix); pw.print("recentCallingPackage=");
                 pw.println(mRecentCallingPackage);
+        pw.print(prefix); pw.print("recentCallingUid=");
+        pw.println(mRecentCallingUid);
         pw.print(prefix); pw.print("allowStartForeground=");
         pw.println(mAllowStartForeground);
         pw.print(prefix); pw.print("infoAllowStartForeground=");
@@ -894,13 +901,13 @@
         return false;
     }
 
-    public void updateWhitelistManager() {
-        whitelistManager = false;
+    public void updateAllowlistManager() {
+        allowlistManager = false;
         for (int conni=connections.size()-1; conni>=0; conni--) {
             ArrayList<ConnectionRecord> cr = connections.valueAt(conni);
             for (int i=0; i<cr.size(); i++) {
                 if ((cr.get(i).flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
-                    whitelistManager = true;
+                    allowlistManager = true;
                     return;
                 }
             }
diff --git a/services/core/java/com/android/server/am/StrictModeViolationDialog.java b/services/core/java/com/android/server/am/StrictModeViolationDialog.java
index 4cc1fc1..9dddd65 100644
--- a/services/core/java/com/android/server/am/StrictModeViolationDialog.java
+++ b/services/core/java/com/android/server/am/StrictModeViolationDialog.java
@@ -82,6 +82,11 @@
                 DISMISS_TIMEOUT);
     }
 
+    @Override
+    protected void closeDialog() {
+        mHandler.obtainMessage(ACTION_OK).sendToTarget();
+    }
+
     private final Handler mHandler = new Handler() {
         public void handleMessage(Message msg) {
             synchronized (mService.mProcLock) {
diff --git a/services/core/java/com/android/server/am/TEST_MAPPING b/services/core/java/com/android/server/am/TEST_MAPPING
index 4061df4..03eddc9 100644
--- a/services/core/java/com/android/server/am/TEST_MAPPING
+++ b/services/core/java/com/android/server/am/TEST_MAPPING
@@ -44,6 +44,23 @@
           "exclude-annotation": "androidx.test.filters.FlakyTest"
         }
       ]
+    },
+    {
+      "file_patterns": ["Battery[^/]*\\.java", "MeasuredEnergy[^/]*\\.java"],
+      "name": "FrameworksCoreTests",
+      "options": [
+        { "include-filter": "com.android.internal.os.BatteryStatsTests" },
+        { "exclude-annotation": "com.android.internal.os.SkipPresubmit" }
+      ]
+    },
+    {
+      "file_patterns": ["Battery[^/]*\\.java", "MeasuredEnergy[^/]*\\.java"],
+      "name": "FrameworksServicesTests",
+      "options": [
+        { "include-filter": "com.android.server.am.BatteryStatsServiceTest" },
+        { "include-filter": "com.android.server.am.MeasuredEnergySnapshotTest" },
+        { "include-filter": "com.android.server.am.BatteryExternalStatsWorkerTest" }
+      ]
     }
   ],
   "postsubmit": [
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 6dd78e7..caf2510 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -27,6 +27,9 @@
 import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
 import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
 import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
+import static android.os.PowerWhitelistManager.REASON_BOOT_COMPLETED;
+import static android.os.PowerWhitelistManager.REASON_LOCKED_BOOT_COMPLETED;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
 import static android.os.Process.SHELL_UID;
 import static android.os.Process.SYSTEM_UID;
 
@@ -74,6 +77,7 @@
 import android.os.IUserManager;
 import android.os.Looper;
 import android.os.Message;
+import android.os.PowerWhitelistManager;
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -522,7 +526,8 @@
                 mInjector.broadcastIntent(intent, null, resultTo, 0, null, null,
                         new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
                         AppOpsManager.OP_NONE,
-                        getTemporaryAppWhitelistBroadcastOptions().toBundle(), true,
+                        getTemporaryAppAllowlistBroadcastOptions(REASON_LOCKED_BOOT_COMPLETED)
+                                .toBundle(), true,
                         false, MY_PID, SYSTEM_UID,
                         Binder.getCallingUid(), Binder.getCallingPid(), userId);
             }
@@ -770,9 +775,8 @@
                     }, 0, null, null,
                     new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
                     AppOpsManager.OP_NONE,
-                    getTemporaryAppWhitelistBroadcastOptions().toBundle(), true,
-                    false, MY_PID, SYSTEM_UID,
-                    callingUid, callingPid, userId);
+                    getTemporaryAppAllowlistBroadcastOptions(REASON_BOOT_COMPLETED).toBundle(),
+                    true, false, MY_PID, SYSTEM_UID, callingUid, callingPid, userId);
         });
     }
 
@@ -2811,7 +2815,8 @@
         }
     }
 
-    private BroadcastOptions getTemporaryAppWhitelistBroadcastOptions() {
+    private BroadcastOptions getTemporaryAppAllowlistBroadcastOptions(
+            @PowerWhitelistManager.ReasonCode int reasonCode) {
         long duration = 10_000;
         final ActivityManagerInternal amInternal =
                 LocalServices.getService(ActivityManagerInternal.class);
@@ -2819,9 +2824,8 @@
             duration = amInternal.getBootTimeTempAllowListDuration();
         }
         final BroadcastOptions bOptions = BroadcastOptions.makeBasic();
-        bOptions.setTemporaryAppWhitelistDuration(
-                BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
-                duration);
+        bOptions.setTemporaryAppAllowlist(duration,
+                TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, reasonCode, "");
         return bOptions;
     }
 
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index 33bdac2..32ae878 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -57,10 +57,13 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.SystemService;
 
 import java.io.File;
 import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -511,6 +514,37 @@
         return mIsServiceEnabled;
     }
 
+    private void dump(PrintWriter pw) {
+        // Check usage stats permission since hibernation indirectly informs usage.
+        if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
+
+        IndentingPrintWriter idpw = new IndentingPrintWriter(pw, "  ");
+
+        synchronized (mLock) {
+            final int userCount = mUserStates.size();
+            for (int i = 0; i < userCount; i++) {
+                final int userId = mUserStates.keyAt(i);
+                idpw.print("User Level Hibernation States, ");
+                idpw.printPair("user", userId);
+                idpw.println();
+                Map<String, UserLevelState> stateMap = mUserStates.get(i);
+                idpw.increaseIndent();
+                for (UserLevelState state : stateMap.values()) {
+                    idpw.print(state);
+                    idpw.println();
+                }
+                idpw.decreaseIndent();
+            }
+            idpw.println();
+            idpw.print("Global Level Hibernation States");
+            idpw.println();
+            for (GlobalLevelState state : mGlobalHibernationStates.values()) {
+                idpw.print(state);
+                idpw.println();
+            }
+        }
+    }
+
     private final AppHibernationServiceStub mServiceStub = new AppHibernationServiceStub(this);
 
     static final class AppHibernationServiceStub extends IAppHibernationService.Stub {
@@ -547,6 +581,12 @@
             new AppHibernationShellCommand(mService).exec(this, in, out, err, args, callback,
                     resultReceiver);
         }
+
+        @Override
+        protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
+                @Nullable String[] args) {
+            mService.dump(fout);
+        }
     }
 
     // Broadcast receiver for package add/removal events
diff --git a/services/core/java/com/android/server/apphibernation/GlobalLevelState.java b/services/core/java/com/android/server/apphibernation/GlobalLevelState.java
index 4f75675..baa84b7 100644
--- a/services/core/java/com/android/server/apphibernation/GlobalLevelState.java
+++ b/services/core/java/com/android/server/apphibernation/GlobalLevelState.java
@@ -22,4 +22,12 @@
 final class GlobalLevelState {
     public String packageName;
     public boolean hibernated;
+
+    @Override
+    public String toString() {
+        return "GlobalLevelState{"
+                + "packageName='" + packageName + '\''
+                + ", hibernated=" + hibernated
+                + '}';
+    }
 }
diff --git a/services/core/java/com/android/server/apphibernation/UserLevelState.java b/services/core/java/com/android/server/apphibernation/UserLevelState.java
index c66dad8..272d3d1 100644
--- a/services/core/java/com/android/server/apphibernation/UserLevelState.java
+++ b/services/core/java/com/android/server/apphibernation/UserLevelState.java
@@ -22,4 +22,12 @@
 final class UserLevelState {
     public String packageName;
     public boolean hibernated;
+
+    @Override
+    public String toString() {
+        return "UserLevelState{"
+                + "packageName='" + packageName + '\''
+                + ", hibernated=" + hibernated
+                + '}';
+    }
 }
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index a776458..11125dd 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -339,7 +339,10 @@
     SparseIntArray mProfileOwners;
 
     @GuardedBy("this")
-    private CheckOpsDelegate mCheckOpsDelegate;
+    private CheckOpsDelegate mAppOpsPolicy;
+
+    @GuardedBy("this")
+    private CheckOpsDelegateDispatcher mCheckOpsDelegateDispatcher;
 
     /**
       * Reverse lookup for {@link AppOpsManager#opToSwitch(int)}. Initialized once and never
@@ -840,11 +843,15 @@
         public void accessed(int proxyUid, @Nullable String proxyPackageName,
                 @Nullable String proxyAttributionTag, @AppOpsManager.UidState int uidState,
                 @OpFlags int flags) {
-            accessed(System.currentTimeMillis(), -1, proxyUid, proxyPackageName,
+            long accessTime = System.currentTimeMillis();
+            accessed(accessTime, -1, proxyUid, proxyPackageName,
                     proxyAttributionTag, uidState, flags);
 
             mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName,
                     tag, uidState, flags);
+
+            mHistoricalRegistry.mDiscreteRegistry.recordDiscreteAccess(parent.uid,
+                    parent.packageName, parent.op, tag, flags, uidState, accessTime, -1);
         }
 
         /**
@@ -1001,8 +1008,10 @@
                 OpEventProxyInfo proxyCopy = event.getProxy() != null
                         ? new OpEventProxyInfo(event.getProxy()) : null;
 
+                long accessDurationMillis =
+                        SystemClock.elapsedRealtime() - event.getStartElapsedTime();
                 NoteOpEvent finishedEvent = new NoteOpEvent(event.getStartTime(),
-                        SystemClock.elapsedRealtime() - event.getStartElapsedTime(), proxyCopy);
+                        accessDurationMillis, proxyCopy);
                 mAccessEvents.put(makeKey(event.getUidState(), event.getFlags()),
                         finishedEvent);
 
@@ -1010,6 +1019,10 @@
                         parent.packageName, tag, event.getUidState(),
                         event.getFlags(), finishedEvent.getDuration());
 
+                mHistoricalRegistry.mDiscreteRegistry.recordDiscreteAccess(parent.uid,
+                        parent.packageName, parent.op, tag, event.getFlags(), event.getUidState(),
+                        event.getStartTime(), accessDurationMillis);
+
                 mInProgressStartOpEventPool.release(event);
 
                 if (mInProgressEvents.isEmpty()) {
@@ -1770,6 +1783,17 @@
         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
     }
 
+    /**
+     * Sets a policy for handling app ops.
+     *
+     * @param appOpsPolicy The policy.
+     */
+    public void setAppOpsPolicy(@Nullable CheckOpsDelegate appOpsPolicy) {
+        synchronized (AppOpsService.this) {
+            mAppOpsPolicy = appOpsPolicy;
+        }
+    }
+
     public void packageRemoved(int uid, String packageName) {
         synchronized (this) {
             UidState uidState = mUidStates.get(uid);
@@ -2073,8 +2097,8 @@
 
     @Override
     public void getHistoricalOps(int uid, String packageName, String attributionTag,
-            List<String> opNames, int filter, long beginTimeMillis, long endTimeMillis,
-            int flags, RemoteCallback callback) {
+            List<String> opNames, int dataType, int filter, long beginTimeMillis,
+            long endTimeMillis, int flags, RemoteCallback callback) {
         PackageManager pm = mContext.getPackageManager();
 
         ensureHistoricalOpRequestIsValid(uid, packageName, attributionTag, opNames, filter,
@@ -2106,14 +2130,14 @@
 
         // Must not hold the appops lock
         mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOps,
-                mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, filter,
-                beginTimeMillis, endTimeMillis, flags, callback).recycleOnUse());
+                mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, dataType,
+                filter, beginTimeMillis, endTimeMillis, flags, callback).recycleOnUse());
     }
 
     @Override
     public void getHistoricalOpsFromDiskRaw(int uid, String packageName, String attributionTag,
-            List<String> opNames, int filter, long beginTimeMillis, long endTimeMillis,
-            int flags, RemoteCallback callback) {
+            List<String> opNames, int dataType, int filter, long beginTimeMillis,
+            long endTimeMillis, int flags, RemoteCallback callback) {
         ensureHistoricalOpRequestIsValid(uid, packageName, attributionTag, opNames, filter,
                 beginTimeMillis, endTimeMillis, flags);
         Objects.requireNonNull(callback, "callback cannot be null");
@@ -2126,7 +2150,7 @@
 
         // Must not hold the appops lock
         mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOpsFromDiskRaw,
-                mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray,
+                mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, dataType,
                 filter, beginTimeMillis, endTimeMillis, flags, callback).recycleOnUse());
     }
 
@@ -2868,13 +2892,19 @@
 
     public CheckOpsDelegate getAppOpsServiceDelegate() {
         synchronized (this) {
-            return mCheckOpsDelegate;
+            return (mCheckOpsDelegateDispatcher != null)
+                    ? mCheckOpsDelegateDispatcher.getCheckOpsDelegate()
+                    : null;
         }
     }
 
     public void setAppOpsServiceDelegate(CheckOpsDelegate delegate) {
         synchronized (this) {
-            mCheckOpsDelegate = delegate;
+            if (delegate != null) {
+                mCheckOpsDelegateDispatcher = new CheckOpsDelegateDispatcher(delegate);
+            } else {
+                mCheckOpsDelegateDispatcher = null;
+            }
         }
     }
 
@@ -2889,19 +2919,28 @@
     }
 
     private int checkOperationInternal(int code, int uid, String packageName, boolean raw) {
-        final CheckOpsDelegate delegate;
-        synchronized (this) {
-            delegate = mCheckOpsDelegate;
+        final CheckOpsDelegate policy;
+        final CheckOpsDelegateDispatcher delegateDispatcher;
+        synchronized (AppOpsService.this) {
+            policy = mAppOpsPolicy;
+            delegateDispatcher = mCheckOpsDelegateDispatcher;
         }
-        if (delegate == null) {
-            return checkOperationImpl(code, uid, packageName, raw);
+        if (policy != null) {
+            if (delegateDispatcher != null) {
+                return policy.checkOperation(code, uid, packageName, raw,
+                        delegateDispatcher::checkOperationImpl);
+            } else {
+                return policy.checkOperation(code, uid, packageName, raw,
+                        AppOpsService.this::checkOperationImpl);
+            }
+        } else if (delegateDispatcher != null) {
+            delegateDispatcher.getCheckOpsDelegate().checkOperation(code, uid,
+                    packageName, raw, AppOpsService.this::checkOperationImpl);
         }
-        return delegate.checkOperation(code, uid, packageName, raw,
-                    AppOpsService.this::checkOperationImpl);
+        return checkOperationImpl(code, uid, packageName, raw);
     }
 
-    private int checkOperationImpl(int code, int uid, String packageName,
-                boolean raw) {
+    private int checkOperationImpl(int code, int uid, String packageName, boolean raw) {
         verifyIncomingOp(code);
         verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
 
@@ -2956,15 +2995,25 @@
 
     @Override
     public int checkAudioOperation(int code, int usage, int uid, String packageName) {
-        final CheckOpsDelegate delegate;
-        synchronized (this) {
-            delegate = mCheckOpsDelegate;
+        final CheckOpsDelegate policy;
+        final CheckOpsDelegateDispatcher delegateDispatcher;
+        synchronized (AppOpsService.this) {
+            policy = mAppOpsPolicy;
+            delegateDispatcher = mCheckOpsDelegateDispatcher;
         }
-        if (delegate == null) {
-            return checkAudioOperationImpl(code, usage, uid, packageName);
+        if (policy != null) {
+            if (delegateDispatcher != null) {
+                return policy.checkAudioOperation(code, usage, uid, packageName,
+                        delegateDispatcher::checkAudioOperationImpl);
+            } else {
+                return policy.checkAudioOperation(code, usage, uid, packageName,
+                        AppOpsService.this::checkAudioOperationImpl);
+            }
+        } else if (delegateDispatcher != null) {
+            delegateDispatcher.getCheckOpsDelegate().checkAudioOperation(code, usage,
+                    uid, packageName, AppOpsService.this::checkAudioOperationImpl);
         }
-        return delegate.checkAudioOperation(code, usage, uid, packageName,
-                AppOpsService.this::checkAudioOperationImpl);
+        return checkAudioOperationImpl(code, usage, uid, packageName);
     }
 
     private int checkAudioOperationImpl(int code, int usage, int uid, String packageName) {
@@ -3078,17 +3127,29 @@
     @Override
     public int noteOperation(int code, int uid, String packageName, String attributionTag,
             boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage) {
-        final CheckOpsDelegate delegate;
-        synchronized (this) {
-            delegate = mCheckOpsDelegate;
+        final CheckOpsDelegate policy;
+        final CheckOpsDelegateDispatcher delegateDispatcher;
+        synchronized (AppOpsService.this) {
+            policy = mAppOpsPolicy;
+            delegateDispatcher = mCheckOpsDelegateDispatcher;
         }
-        if (delegate == null) {
-            return noteOperationImpl(code, uid, packageName, attributionTag,
-                    shouldCollectAsyncNotedOp, message, shouldCollectMessage);
+        if (policy != null) {
+            if (delegateDispatcher != null) {
+                return policy.noteOperation(code, uid, packageName, attributionTag,
+                        shouldCollectAsyncNotedOp, message, shouldCollectMessage,
+                        delegateDispatcher::noteOperationImpl);
+            } else {
+                return policy.noteOperation(code, uid, packageName, attributionTag,
+                        shouldCollectAsyncNotedOp, message, shouldCollectMessage,
+                        AppOpsService.this::noteOperationImpl);
+            }
+        } else if (delegateDispatcher != null) {
+            delegateDispatcher.getCheckOpsDelegate().noteOperation(code, uid, packageName,
+                    attributionTag, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
+                    AppOpsService.this::noteOperationImpl);
         }
-        return delegate.noteOperation(code, uid, packageName, attributionTag,
-                shouldCollectAsyncNotedOp, message, shouldCollectMessage,
-                AppOpsService.this::noteOperationImpl);
+        return noteOperationImpl(code, uid, packageName, attributionTag,
+                shouldCollectAsyncNotedOp, message, shouldCollectMessage);
     }
 
     private int noteOperationImpl(int code, int uid, @Nullable String packageName,
@@ -4708,6 +4769,7 @@
                 mFile.failWrite(stream);
             }
         }
+        mHistoricalRegistry.mDiscreteRegistry.writeAndClearAccessHistory();
     }
 
     static class Shell extends ShellCommand {
@@ -6064,6 +6126,7 @@
                 "clearHistory");
         // Must not hold the appops lock
         mHistoricalRegistry.clearHistory();
+        mHistoricalRegistry.mDiscreteRegistry.clearHistory();
     }
 
     @Override
@@ -6589,7 +6652,6 @@
         }
     }
 
-
     /**
      * Async task for writing note op stack trace, op code, package name and version to file
      * More specifically, writes all the collected ops from {@link #mNoteOpCallerStacktraces}
@@ -6726,4 +6788,34 @@
             }
         }
     }
+
+    private final class CheckOpsDelegateDispatcher {
+        private final @NonNull CheckOpsDelegate mCheckOpsDelegate;
+
+        CheckOpsDelegateDispatcher(@NonNull CheckOpsDelegate checkOpsDelegate) {
+            mCheckOpsDelegate = checkOpsDelegate;
+        }
+
+        public @NonNull CheckOpsDelegate getCheckOpsDelegate() {
+            return mCheckOpsDelegate;
+        }
+
+        public int checkOperationImpl(int code, int uid, String packageName, boolean raw) {
+            return mCheckOpsDelegate.checkOperation(code, uid, packageName, raw,
+                    AppOpsService.this::checkOperationImpl);
+        }
+
+        public int checkAudioOperationImpl(int code, int usage, int uid, String packageName) {
+            return mCheckOpsDelegate.checkAudioOperation(code, usage, uid, packageName,
+                    AppOpsService.this::checkAudioOperationImpl);
+        }
+
+        public int noteOperationImpl(int code, int uid, @Nullable String packageName,
+                @Nullable String featureId, boolean shouldCollectAsyncNotedOp,
+                @Nullable String message, boolean shouldCollectMessage) {
+            return mCheckOpsDelegate.noteOperation(code, uid, packageName, featureId,
+                    shouldCollectAsyncNotedOp, message, shouldCollectMessage,
+                    AppOpsService.this::noteOperationImpl);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/appop/DiscreteRegistry.java b/services/core/java/com/android/server/appop/DiscreteRegistry.java
new file mode 100644
index 0000000..7699045
--- /dev/null
+++ b/services/core/java/com/android/server/appop/DiscreteRegistry.java
@@ -0,0 +1,616 @@
+/*
+ * 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.appop;
+
+import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG;
+import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
+import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
+import static android.app.AppOpsManager.FILTER_BY_UID;
+import static android.app.AppOpsManager.OP_CAMERA;
+import static android.app.AppOpsManager.OP_COARSE_LOCATION;
+import static android.app.AppOpsManager.OP_FINE_LOCATION;
+import static android.app.AppOpsManager.OP_FLAG_SELF;
+import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
+import static android.app.AppOpsManager.OP_RECORD_AUDIO;
+
+import static java.lang.Math.max;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppOpsManager;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.Process;
+import android.util.ArrayMap;
+import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
+import android.util.Xml;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.XmlUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * This class manages information about recent accesses to ops for
+ * permission usage timeline.
+ *
+ * The timeline history is kept for limited time (initial default is 24 hours) and
+ * discarded after that.
+ *
+ * Every time state is saved (default is 30 minutes), memory state is dumped to a
+ * new file and memory state is cleared. Files older than time limit are deleted
+ * during the process.
+ *
+ * When request comes in, files are read and requested information is collected
+ * and delivered.
+ */
+
+final class DiscreteRegistry {
+    static final String TIMELINE_FILE_SUFFIX = "tl";
+    private static final String TAG = DiscreteRegistry.class.getSimpleName();
+
+    private static final long TIMELINE_HISTORY_CUTOFF = Duration.ofHours(24).toMillis();
+    private static final String TAG_HISTORY = "h";
+    private static final String ATTR_VERSION = "v";
+    private static final int CURRENT_VERSION = 1;
+
+    private static final String TAG_UID = "u";
+    private static final String ATTR_UID = "ui";
+
+    private static final String TAG_PACKAGE = "p";
+    private static final String ATTR_PACKAGE_NAME = "pn";
+
+    private static final String TAG_OP = "o";
+    private static final String ATTR_OP_ID = "op";
+
+    private static final String TAG_TAG = "a";
+    private static final String ATTR_TAG = "at";
+
+    private static final String TAG_ENTRY = "e";
+    private static final String ATTR_NOTE_TIME = "nt";
+    private static final String ATTR_NOTE_DURATION = "nd";
+    private static final String ATTR_UID_STATE = "us";
+    private static final String ATTR_FLAGS = "f";
+
+    // Lock for read/write access to on disk state
+    private final Object mOnDiskLock = new Object();
+
+    //Lock for read/write access to in memory state
+    private final @NonNull Object mInMemoryLock;
+
+    @GuardedBy("mOnDiskLock")
+    private final File mDiscreteAccessDir;
+
+    @GuardedBy("mInMemoryLock")
+    private DiscreteOps mDiscreteOps;
+
+    DiscreteRegistry(Object inMemoryLock) {
+        mInMemoryLock = inMemoryLock;
+        mDiscreteAccessDir = new File(new File(Environment.getDataSystemDirectory(), "appops"),
+                "discrete");
+        createDiscreteAccessDir();
+        mDiscreteOps = new DiscreteOps();
+    }
+
+    private void createDiscreteAccessDir() {
+        if (!mDiscreteAccessDir.exists()) {
+            if (!mDiscreteAccessDir.mkdirs()) {
+                Slog.e(TAG, "Failed to create DiscreteRegistry directory");
+            }
+            FileUtils.setPermissions(mDiscreteAccessDir.getPath(),
+                    FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
+        }
+    }
+
+    void recordDiscreteAccess(int uid, String packageName, int op, @Nullable String attributionTag,
+            @AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState, long accessTime,
+            long accessDuration) {
+        if (!isDiscreteOp(op, uid, flags)) {
+            return;
+        }
+        synchronized (mInMemoryLock) {
+            mDiscreteOps.addDiscreteAccess(op, uid, packageName, attributionTag, flags, uidState,
+                    accessTime, accessDuration);
+        }
+    }
+
+    void writeAndClearAccessHistory() {
+        synchronized (mOnDiskLock) {
+            final File[] files = mDiscreteAccessDir.listFiles();
+            if (files != null && files.length > 0) {
+                for (File f : files) {
+                    final String fileName = f.getName();
+                    if (!fileName.endsWith(TIMELINE_FILE_SUFFIX)) {
+                        continue;
+                    }
+                    try {
+                        long timestamp = Long.valueOf(fileName.substring(0,
+                                fileName.length() - TIMELINE_FILE_SUFFIX.length()));
+                        if (Instant.now().minus(TIMELINE_HISTORY_CUTOFF,
+                                ChronoUnit.MILLIS).toEpochMilli() > timestamp) {
+                            f.delete();
+                            Slog.e(TAG, "Deleting file " + fileName);
+
+                        }
+                    } catch (Throwable t) {
+                        Slog.e(TAG, "Error while cleaning timeline files: " + t.getMessage() + " "
+                                + t.getStackTrace());
+                    }
+                }
+            }
+        }
+        DiscreteOps discreteOps;
+        synchronized (mInMemoryLock) {
+            discreteOps = mDiscreteOps;
+            mDiscreteOps = new DiscreteOps();
+        }
+        if (discreteOps.isEmpty()) {
+            return;
+        }
+        long currentTimeStamp = Instant.now().toEpochMilli();
+        try {
+            final File file = new File(mDiscreteAccessDir, currentTimeStamp + TIMELINE_FILE_SUFFIX);
+            discreteOps.writeToFile(file);
+        } catch (Throwable t) {
+            Slog.e(TAG,
+                    "Error writing timeline state: " + t.getMessage() + " "
+                            + Arrays.toString(t.getStackTrace()));
+        }
+    }
+
+    void getHistoricalDiscreteOps(AppOpsManager.HistoricalOps result, long beginTimeMillis,
+            long endTimeMillis, @AppOpsManager.HistoricalOpsRequestFilter int filter, int uidFilter,
+            @Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
+            @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
+        writeAndClearAccessHistory();
+        DiscreteOps discreteOps = new DiscreteOps();
+        readDiscreteOpsFromDisk(discreteOps, beginTimeMillis, endTimeMillis, filter, uidFilter,
+                packageNameFilter, opNamesFilter, attributionTagFilter, flagsFilter);
+        discreteOps.applyToHistoricalOps(result);
+        return;
+    }
+
+    private void readDiscreteOpsFromDisk(DiscreteOps discreteOps, long beginTimeMillis,
+            long endTimeMillis, @AppOpsManager.HistoricalOpsRequestFilter int filter, int uidFilter,
+            @Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
+            @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
+        synchronized (mOnDiskLock) {
+            long historyBeginTimeMillis = Instant.now().minus(TIMELINE_HISTORY_CUTOFF,
+                    ChronoUnit.MILLIS).toEpochMilli();
+            if (historyBeginTimeMillis > endTimeMillis) {
+                return;
+            }
+            beginTimeMillis = max(beginTimeMillis, historyBeginTimeMillis);
+
+            final File[] files = mDiscreteAccessDir.listFiles();
+            if (files != null && files.length > 0) {
+                for (File f : files) {
+                    final String fileName = f.getName();
+                    if (!fileName.endsWith(TIMELINE_FILE_SUFFIX)) {
+                        continue;
+                    }
+                    long timestamp = Long.valueOf(fileName.substring(0,
+                            fileName.length() - TIMELINE_FILE_SUFFIX.length()));
+                    if (timestamp < beginTimeMillis) {
+                        continue;
+                    }
+                    discreteOps.readFromFile(f, beginTimeMillis, endTimeMillis, filter, uidFilter,
+                            packageNameFilter, opNamesFilter, attributionTagFilter, flagsFilter);
+                }
+            }
+        }
+    }
+
+    void clearHistory() {
+        synchronized (mOnDiskLock) {
+            synchronized (mInMemoryLock) {
+                mDiscreteOps = new DiscreteOps();
+            }
+            FileUtils.deleteContentsAndDir(mDiscreteAccessDir);
+            createDiscreteAccessDir();
+        }
+    }
+
+    public static boolean isDiscreteOp(int op, int uid, @AppOpsManager.OpFlags int flags) {
+        if (!isDiscreteOp(op)) {
+            return false;
+        }
+        if (!isDiscreteUid(uid)) {
+            return false;
+        }
+        if ((flags & (OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED)) == 0) {
+            return false;
+        }
+        return true;
+    }
+
+    static boolean isDiscreteOp(int op) {
+        if (op != OP_CAMERA && op != OP_RECORD_AUDIO && op != OP_FINE_LOCATION
+                && op != OP_COARSE_LOCATION) {
+            return false;
+        }
+        return true;
+    }
+
+    static boolean isDiscreteUid(int uid) {
+        if (uid < Process.FIRST_APPLICATION_UID) {
+            return false;
+        }
+        return true;
+    }
+
+    private final class DiscreteOps {
+        ArrayMap<Integer, DiscreteUidOps> mUids;
+
+        DiscreteOps() {
+            mUids = new ArrayMap<>();
+        }
+
+        void addDiscreteAccess(int op, int uid, @NonNull String packageName,
+                @Nullable String attributionTag, @AppOpsManager.OpFlags int flags,
+                @AppOpsManager.UidState int uidState, long accessTime, long accessDuration) {
+            getOrCreateDiscreteUidOps(uid).addDiscreteAccess(op, packageName, attributionTag, flags,
+                    uidState, accessTime, accessDuration);
+        }
+
+        private void applyToHistoricalOps(AppOpsManager.HistoricalOps result) {
+            int nUids = mUids.size();
+            for (int i = 0; i < nUids; i++) {
+                mUids.valueAt(i).applyToHistory(result, mUids.keyAt(i));
+            }
+        }
+
+        private void writeToFile(File f) throws Exception {
+            FileOutputStream stream = new FileOutputStream(f);
+            TypedXmlSerializer out = Xml.resolveSerializer(stream);
+
+            out.startDocument(null, true);
+            out.startTag(null, TAG_HISTORY);
+            out.attributeInt(null, ATTR_VERSION, CURRENT_VERSION);
+
+            int nUids = mUids.size();
+            for (int i = 0; i < nUids; i++) {
+                out.startTag(null, TAG_UID);
+                out.attributeInt(null, ATTR_UID, mUids.keyAt(i));
+                mUids.valueAt(i).serialize(out);
+                out.endTag(null, TAG_UID);
+            }
+            out.endTag(null, TAG_HISTORY);
+            out.endDocument();
+            stream.close();
+        }
+
+        private DiscreteUidOps getOrCreateDiscreteUidOps(int uid) {
+            DiscreteUidOps result = mUids.get(uid);
+            if (result == null) {
+                result = new DiscreteUidOps();
+                mUids.put(uid, result);
+            }
+            return result;
+        }
+
+        boolean isEmpty() {
+            return mUids.isEmpty();
+        }
+
+        private void readFromFile(File f, long beginTimeMillis, long endTimeMillis,
+                @AppOpsManager.HistoricalOpsRequestFilter int filter,
+                int uidFilter, @Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
+                @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
+            try {
+                FileInputStream stream = new FileInputStream(f);
+                TypedXmlPullParser parser = Xml.resolvePullParser(stream);
+                XmlUtils.beginDocument(parser, TAG_HISTORY);
+
+                // We haven't released version 1 and have more detailed
+                // accounting - just nuke the current state
+                final int version = parser.getAttributeInt(null, ATTR_VERSION);
+                if (version != CURRENT_VERSION) {
+                    throw new IllegalStateException("Dropping unsupported discrete history " + f);
+                }
+
+                int depth = parser.getDepth();
+                while (XmlUtils.nextElementWithin(parser, depth)) {
+                    if (TAG_UID.equals(parser.getName())) {
+                        int uid = parser.getAttributeInt(null, ATTR_UID, -1);
+                        if ((filter & FILTER_BY_UID) != 0 && uid != uidFilter) {
+                            continue;
+                        }
+                        getOrCreateDiscreteUidOps(uid).deserialize(parser, beginTimeMillis,
+                                endTimeMillis, filter, packageNameFilter, opNamesFilter,
+                                attributionTagFilter, flagsFilter);
+                    }
+                }
+            } catch (Throwable t) {
+                Slog.e(TAG, "Failed to read file " + f.getName() + " " + t.getMessage() + " "
+                        + Arrays.toString(t.getStackTrace()));
+            }
+
+        }
+    }
+
+    private final class DiscreteUidOps {
+        ArrayMap<String, DiscretePackageOps> mPackages;
+
+        DiscreteUidOps() {
+            mPackages = new ArrayMap<>();
+        }
+
+        void addDiscreteAccess(int op, @NonNull String packageName, @Nullable String attributionTag,
+                @AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState,
+                long accessTime, long accessDuration) {
+            getOrCreateDiscretePackageOps(packageName).addDiscreteAccess(op, attributionTag, flags,
+                    uidState, accessTime, accessDuration);
+        }
+
+        private DiscretePackageOps getOrCreateDiscretePackageOps(String packageName) {
+            DiscretePackageOps result = mPackages.get(packageName);
+            if (result == null) {
+                result = new DiscretePackageOps();
+                mPackages.put(packageName, result);
+            }
+            return result;
+        }
+
+        private void applyToHistory(AppOpsManager.HistoricalOps result, int uid) {
+            int nPackages = mPackages.size();
+            for (int i = 0; i < nPackages; i++) {
+                mPackages.valueAt(i).applyToHistory(result, uid, mPackages.keyAt(i));
+            }
+        }
+
+        void serialize(TypedXmlSerializer out) throws Exception {
+            int nPackages = mPackages.size();
+            for (int i = 0; i < nPackages; i++) {
+                out.startTag(null, TAG_PACKAGE);
+                out.attribute(null, ATTR_PACKAGE_NAME, mPackages.keyAt(i));
+                mPackages.valueAt(i).serialize(out);
+                out.endTag(null, TAG_PACKAGE);
+            }
+        }
+
+        void deserialize(TypedXmlPullParser parser, long beginTimeMillis,
+                long endTimeMillis, @AppOpsManager.HistoricalOpsRequestFilter int filter,
+                @Nullable String packageNameFilter,
+                @Nullable String[] opNamesFilter, @Nullable String attributionTagFilter,
+                @AppOpsManager.OpFlags int flagsFilter) throws Exception {
+            int depth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, depth)) {
+                if (TAG_PACKAGE.equals(parser.getName())) {
+                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
+                    if ((filter & FILTER_BY_PACKAGE_NAME) != 0
+                            && !packageName.equals(packageNameFilter)) {
+                        continue;
+                    }
+                    getOrCreateDiscretePackageOps(packageName).deserialize(parser, beginTimeMillis,
+                            endTimeMillis, filter, opNamesFilter, attributionTagFilter,
+                            flagsFilter);
+                }
+            }
+        }
+    }
+
+    private final class DiscretePackageOps {
+        ArrayMap<Integer, DiscreteOp> mPackageOps;
+
+        DiscretePackageOps() {
+            mPackageOps = new ArrayMap<>();
+        }
+
+        void addDiscreteAccess(int op, @Nullable String attributionTag,
+                @AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState,
+                long accessTime, long accessDuration) {
+            getOrCreateDiscreteOp(op).addDiscreteAccess(attributionTag, flags, uidState, accessTime,
+                    accessDuration);
+        }
+
+        private DiscreteOp getOrCreateDiscreteOp(int op) {
+            DiscreteOp result = mPackageOps.get(op);
+            if (result == null) {
+                result = new DiscreteOp();
+                mPackageOps.put(op, result);
+            }
+            return result;
+        }
+
+        private void applyToHistory(AppOpsManager.HistoricalOps result, int uid,
+                @NonNull String packageName) {
+            int nPackageOps = mPackageOps.size();
+            for (int i = 0; i < nPackageOps; i++) {
+                mPackageOps.valueAt(i).applyToHistory(result, uid, packageName,
+                        mPackageOps.keyAt(i));
+            }
+        }
+
+        void serialize(TypedXmlSerializer out) throws Exception {
+            int nOps = mPackageOps.size();
+            for (int i = 0; i < nOps; i++) {
+                out.startTag(null, TAG_OP);
+                out.attributeInt(null, ATTR_OP_ID, mPackageOps.keyAt(i));
+                mPackageOps.valueAt(i).serialize(out);
+                out.endTag(null, TAG_OP);
+            }
+        }
+
+        void deserialize(TypedXmlPullParser parser, long beginTimeMillis, long endTimeMillis,
+                @AppOpsManager.HistoricalOpsRequestFilter int filter,
+                @Nullable String[] opNamesFilter, @Nullable String attributionTagFilter,
+                @AppOpsManager.OpFlags int flagsFilter) throws Exception {
+            int depth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, depth)) {
+                if (TAG_OP.equals(parser.getName())) {
+                    int op = parser.getAttributeInt(null, ATTR_OP_ID);
+                    if ((filter & FILTER_BY_OP_NAMES) != 0 && !ArrayUtils.contains(opNamesFilter,
+                            AppOpsManager.opToPublicName(op))) {
+                        continue;
+                    }
+                    getOrCreateDiscreteOp(op).deserialize(parser, beginTimeMillis, endTimeMillis,
+                            filter, attributionTagFilter, flagsFilter);
+                }
+            }
+        }
+    }
+
+    private final class DiscreteOp {
+        ArrayMap<String, List<DiscreteOpEvent>> mAttributedOps;
+
+        DiscreteOp() {
+            mAttributedOps = new ArrayMap<>();
+        }
+
+        void addDiscreteAccess(@Nullable String attributionTag,
+                @AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState,
+                long accessTime, long accessDuration) {
+            List<DiscreteOpEvent> attributedOps = getOrCreateDiscreteOpEventsList(
+                    attributionTag);
+            accessTime = Instant.ofEpochMilli(accessTime).truncatedTo(
+                    ChronoUnit.MINUTES).toEpochMilli();
+
+            int nAttributedOps = attributedOps.size();
+            for (int i = nAttributedOps - 1; i >= 0; i--) {
+                DiscreteOpEvent previousOp = attributedOps.get(i);
+                if (previousOp.mNoteTime < accessTime) {
+                    break;
+                }
+                if (previousOp.mOpFlag == flags && previousOp.mUidState == uidState) {
+                    return;
+                }
+            }
+            attributedOps.add(new DiscreteOpEvent(accessTime, accessDuration, uidState, flags));
+        }
+
+        private List<DiscreteOpEvent> getOrCreateDiscreteOpEventsList(String attributionTag) {
+            List<DiscreteOpEvent> result = mAttributedOps.get(attributionTag);
+            if (result == null) {
+                result = new ArrayList<>();
+                mAttributedOps.put(attributionTag, result);
+            }
+            return result;
+        }
+
+        private void applyToHistory(AppOpsManager.HistoricalOps result, int uid,
+                @NonNull String packageName, int op) {
+            int nOps = mAttributedOps.size();
+            for (int i = 0; i < nOps; i++) {
+                String tag = mAttributedOps.keyAt(i);
+                List<DiscreteOpEvent> events = mAttributedOps.valueAt(i);
+                int nEvents = events.size();
+                for (int j = 0; j < nEvents; j++) {
+                    DiscreteOpEvent event = events.get(j);
+                    result.addDiscreteAccess(op, uid, packageName, tag, event.mUidState,
+                            event.mOpFlag, event.mNoteTime, event.mNoteDuration);
+                }
+            }
+        }
+
+        void serialize(TypedXmlSerializer out) throws Exception {
+            int nAttributions = mAttributedOps.size();
+            for (int i = 0; i < nAttributions; i++) {
+                out.startTag(null, TAG_TAG);
+                String tag = mAttributedOps.keyAt(i);
+                if (tag != null) {
+                    out.attribute(null, ATTR_TAG, mAttributedOps.keyAt(i));
+                }
+                List<DiscreteOpEvent> ops = mAttributedOps.valueAt(i);
+                int nOps = ops.size();
+                for (int j = 0; j < nOps; j++) {
+                    out.startTag(null, TAG_ENTRY);
+                    ops.get(j).serialize(out);
+                    out.endTag(null, TAG_ENTRY);
+                }
+                out.endTag(null, TAG_TAG);
+            }
+        }
+
+        void deserialize(TypedXmlPullParser parser, long beginTimeMillis, long endTimeMillis,
+                @AppOpsManager.HistoricalOpsRequestFilter int filter,
+                @Nullable String attributionTagFilter,
+                @AppOpsManager.OpFlags int flagsFilter) throws Exception {
+            int outerDepth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+                if (TAG_TAG.equals(parser.getName())) {
+                    String attributionTag = parser.getAttributeValue(null, ATTR_TAG);
+                    if ((filter & FILTER_BY_ATTRIBUTION_TAG) != 0 && !attributionTag.equals(
+                            attributionTagFilter)) {
+                        continue;
+                    }
+                    List<DiscreteOpEvent> events = getOrCreateDiscreteOpEventsList(
+                            attributionTag);
+                    int innerDepth = parser.getDepth();
+                    while (XmlUtils.nextElementWithin(parser, innerDepth)) {
+                        if (TAG_ENTRY.equals(parser.getName())) {
+                            long noteTime = parser.getAttributeLong(null, ATTR_NOTE_TIME);
+                            long noteDuration = parser.getAttributeLong(null, ATTR_NOTE_DURATION,
+                                    -1);
+                            int uidState = parser.getAttributeInt(null, ATTR_UID_STATE);
+                            int opFlags = parser.getAttributeInt(null, ATTR_FLAGS);
+                            if ((flagsFilter & opFlags) == 0) {
+                                continue;
+                            }
+                            if ((noteTime + noteDuration < beginTimeMillis
+                                    && noteTime > endTimeMillis)) {
+                                continue;
+                            }
+                            DiscreteOpEvent event = new DiscreteOpEvent(noteTime, noteDuration,
+                                    uidState, opFlags);
+                            events.add(event);
+                        }
+                    }
+                    Collections.sort(events, (a, b) -> a.mNoteTime < b.mNoteTime ? -1
+                            : (a.mNoteTime == b.mNoteTime ? 0 : 1));
+                }
+            }
+        }
+    }
+
+    private final class DiscreteOpEvent {
+        final long mNoteTime;
+        final long mNoteDuration;
+        final @AppOpsManager.UidState int mUidState;
+        final @AppOpsManager.OpFlags int mOpFlag;
+
+        DiscreteOpEvent(long noteTime, long noteDuration, @AppOpsManager.UidState int uidState,
+                @AppOpsManager.OpFlags int opFlag) {
+            mNoteTime = noteTime;
+            mNoteDuration = noteDuration;
+            mUidState = uidState;
+            mOpFlag = opFlag;
+        }
+
+        private void serialize(TypedXmlSerializer out) throws Exception {
+            out.attributeLong(null, ATTR_NOTE_TIME, mNoteTime);
+            if (mNoteDuration != -1) {
+                out.attributeLong(null, ATTR_NOTE_DURATION, mNoteDuration);
+            }
+            out.attributeInt(null, ATTR_UID_STATE, mUidState);
+            out.attributeInt(null, ATTR_FLAGS, mOpFlag);
+        }
+    }
+}
+
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index 17fd32c..1c43fed 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -19,6 +19,8 @@
 import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
 import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
 import static android.app.AppOpsManager.FILTER_BY_UID;
+import static android.app.AppOpsManager.HISTORY_FLAG_AGGREGATE;
+import static android.app.AppOpsManager.HISTORY_FLAG_DISCRETE;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -30,6 +32,7 @@
 import android.app.AppOpsManager.HistoricalPackageOps;
 import android.app.AppOpsManager.HistoricalUidOps;
 import android.app.AppOpsManager.OpFlags;
+import android.app.AppOpsManager.OpHistoryFlags;
 import android.app.AppOpsManager.UidState;
 import android.content.ContentResolver;
 import android.database.ContentObserver;
@@ -61,9 +64,7 @@
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.FgThread;
 
-import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -71,7 +72,6 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -85,7 +85,7 @@
 import java.util.concurrent.TimeUnit;
 
 /**
- * This class managers historical app op state. This includes reading, persistence,
+ * This class manages historical app op state. This includes reading, persistence,
  * accounting, querying.
  * <p>
  * The history is kept forever in multiple files. Each file time contains the
@@ -138,6 +138,8 @@
     private static final String PARAMETER_ASSIGNMENT = "=";
     private static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled";
 
+    volatile @NonNull DiscreteRegistry mDiscreteRegistry;
+
     @GuardedBy("mLock")
     private @NonNull LinkedList<HistoricalOps> mPendingWrites = new LinkedList<>();
 
@@ -199,6 +201,7 @@
 
     HistoricalRegistry(@NonNull Object lock) {
         mInMemoryLock = lock;
+        mDiscreteRegistry = new DiscreteRegistry(lock);
     }
 
     HistoricalRegistry(@NonNull HistoricalRegistry other) {
@@ -352,36 +355,49 @@
         }
     }
 
-    void getHistoricalOpsFromDiskRaw(int uid, @NonNull String packageName,
+    void getHistoricalOpsFromDiskRaw(int uid, @Nullable String packageName,
             @Nullable String attributionTag, @Nullable String[] opNames,
-            @HistoricalOpsRequestFilter int filter, long beginTimeMillis, long endTimeMillis,
-            @OpFlags int flags, @NonNull RemoteCallback callback) {
+            @OpHistoryFlags int historyFlags, @HistoricalOpsRequestFilter int filter,
+            long beginTimeMillis, long endTimeMillis, @OpFlags int flags,
+            @NonNull RemoteCallback callback) {
         if (!isApiEnabled()) {
             callback.sendResult(new Bundle());
             return;
         }
 
-        synchronized (mOnDiskLock) {
-            synchronized (mInMemoryLock) {
-                if (!isPersistenceInitializedMLocked()) {
-                    Slog.e(LOG_TAG, "Interaction before persistence initialized");
-                    callback.sendResult(new Bundle());
-                    return;
+        final HistoricalOps result = new HistoricalOps(beginTimeMillis, endTimeMillis);
+
+        if ((historyFlags & HISTORY_FLAG_AGGREGATE) != 0) {
+            synchronized (mOnDiskLock) {
+                synchronized (mInMemoryLock) {
+                    if (!isPersistenceInitializedMLocked()) {
+                        Slog.e(LOG_TAG, "Interaction before persistence initialized");
+                        callback.sendResult(new Bundle());
+                        return;
+                    }
+                    mPersistence.collectHistoricalOpsDLocked(result, uid, packageName,
+                            attributionTag,
+                            opNames, filter, beginTimeMillis, endTimeMillis, flags);
+
                 }
-                final HistoricalOps result = new HistoricalOps(beginTimeMillis, endTimeMillis);
-                mPersistence.collectHistoricalOpsDLocked(result, uid, packageName, attributionTag,
-                        opNames, filter, beginTimeMillis, endTimeMillis, flags);
-                final Bundle payload = new Bundle();
-                payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, result);
-                callback.sendResult(payload);
             }
         }
+
+        if ((historyFlags & HISTORY_FLAG_DISCRETE) != 0) {
+            mDiscreteRegistry.getHistoricalDiscreteOps(result, beginTimeMillis, endTimeMillis,
+                    filter, uid, packageName, opNames, attributionTag,
+                    flags);
+        }
+
+        final Bundle payload = new Bundle();
+        payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, result);
+        callback.sendResult(payload);
     }
 
-    void getHistoricalOps(int uid, @NonNull String packageName, @Nullable String attributionTag,
-            @Nullable String[] opNames, @HistoricalOpsRequestFilter int filter,
-            long beginTimeMillis, long endTimeMillis, @OpFlags int flags,
-            @NonNull RemoteCallback callback) {
+    void getHistoricalOps(int uid, @Nullable String packageName, @Nullable String attributionTag,
+            @Nullable String[] opNames, @OpHistoryFlags int historyFlags,
+            @HistoricalOpsRequestFilter int filter, long beginTimeMillis, long endTimeMillis,
+            @OpFlags int flags, @NonNull RemoteCallback callback) {
         if (!isApiEnabled()) {
             callback.sendResult(new Bundle());
             return;
@@ -392,6 +408,8 @@
             endTimeMillis = currentTimeMillis;
         }
 
+        final Bundle payload = new Bundle();
+
         // Argument times are based off epoch start while our internal store is
         // based off now, so take this into account.
         final long inMemoryAdjBeginTimeMillis = Math.max(currentTimeMillis - endTimeMillis, 0);
@@ -399,55 +417,63 @@
         final HistoricalOps result = new HistoricalOps(inMemoryAdjBeginTimeMillis,
                 inMemoryAdjEndTimeMillis);
 
-        synchronized (mOnDiskLock) {
-            final List<HistoricalOps> pendingWrites;
-            final HistoricalOps currentOps;
-            boolean collectOpsFromDisk;
-
-            synchronized (mInMemoryLock) {
-                if (!isPersistenceInitializedMLocked()) {
-                    Slog.e(LOG_TAG, "Interaction before persistence initialized");
-                    callback.sendResult(new Bundle());
-                    return;
-                }
-
-                currentOps = getUpdatedPendingHistoricalOpsMLocked(currentTimeMillis);
-                if (!(inMemoryAdjBeginTimeMillis >= currentOps.getEndTimeMillis()
-                        || inMemoryAdjEndTimeMillis <= currentOps.getBeginTimeMillis())) {
-                    // Some of the current batch falls into the query, so extract that.
-                    final HistoricalOps currentOpsCopy = new HistoricalOps(currentOps);
-                    currentOpsCopy.filter(uid, packageName, attributionTag, opNames, filter,
-                            inMemoryAdjBeginTimeMillis, inMemoryAdjEndTimeMillis);
-                    result.merge(currentOpsCopy);
-                }
-                pendingWrites = new ArrayList<>(mPendingWrites);
-                mPendingWrites.clear();
-                collectOpsFromDisk = inMemoryAdjEndTimeMillis > currentOps.getEndTimeMillis();
-            }
-
-            // If the query was only for in-memory state - done.
-            if (collectOpsFromDisk) {
-                // If there is a write in flight we need to force it now
-                persistPendingHistory(pendingWrites);
-                // Collect persisted state.
-                final long onDiskAndInMemoryOffsetMillis = currentTimeMillis
-                        - mNextPersistDueTimeMillis + mBaseSnapshotInterval;
-                final long onDiskAdjBeginTimeMillis = Math.max(inMemoryAdjBeginTimeMillis
-                        - onDiskAndInMemoryOffsetMillis, 0);
-                final long onDiskAdjEndTimeMillis = Math.max(inMemoryAdjEndTimeMillis
-                        - onDiskAndInMemoryOffsetMillis, 0);
-                mPersistence.collectHistoricalOpsDLocked(result, uid, packageName, attributionTag,
-                        opNames, filter, onDiskAdjBeginTimeMillis, onDiskAdjEndTimeMillis, flags);
-            }
-
-            // Rebase the result time to be since epoch.
-            result.setBeginAndEndTime(beginTimeMillis, endTimeMillis);
-
-            // Send back the result.
-            final Bundle payload = new Bundle();
-            payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, result);
-            callback.sendResult(payload);
+        if ((historyFlags & HISTORY_FLAG_DISCRETE) != 0) {
+            mDiscreteRegistry.getHistoricalDiscreteOps(result, beginTimeMillis, endTimeMillis,
+                    filter, uid, packageName, opNames, attributionTag, flags);
         }
+
+        if ((historyFlags & HISTORY_FLAG_AGGREGATE) != 0) {
+            synchronized (mOnDiskLock) {
+                final List<HistoricalOps> pendingWrites;
+                final HistoricalOps currentOps;
+                boolean collectOpsFromDisk;
+
+                synchronized (mInMemoryLock) {
+                    if (!isPersistenceInitializedMLocked()) {
+                        Slog.e(LOG_TAG, "Interaction before persistence initialized");
+                        callback.sendResult(new Bundle());
+                        return;
+                    }
+
+                    currentOps = getUpdatedPendingHistoricalOpsMLocked(currentTimeMillis);
+                    if (!(inMemoryAdjBeginTimeMillis >= currentOps.getEndTimeMillis()
+                            || inMemoryAdjEndTimeMillis <= currentOps.getBeginTimeMillis())) {
+                        // Some of the current batch falls into the query, so extract that.
+                        final HistoricalOps currentOpsCopy = new HistoricalOps(currentOps);
+                        currentOpsCopy.filter(uid, packageName, attributionTag, opNames,
+                                historyFlags, filter, inMemoryAdjBeginTimeMillis,
+                                inMemoryAdjEndTimeMillis);
+                        result.merge(currentOpsCopy);
+                    }
+                    pendingWrites = new ArrayList<>(mPendingWrites);
+                    mPendingWrites.clear();
+                    collectOpsFromDisk = inMemoryAdjEndTimeMillis > currentOps.getEndTimeMillis();
+                }
+
+                // If the query was only for in-memory state - done.
+                if (collectOpsFromDisk) {
+                    // If there is a write in flight we need to force it now
+                    persistPendingHistory(pendingWrites);
+                    // Collect persisted state.
+                    final long onDiskAndInMemoryOffsetMillis = currentTimeMillis
+                            - mNextPersistDueTimeMillis + mBaseSnapshotInterval;
+                    final long onDiskAdjBeginTimeMillis = Math.max(inMemoryAdjBeginTimeMillis
+                            - onDiskAndInMemoryOffsetMillis, 0);
+                    final long onDiskAdjEndTimeMillis = Math.max(inMemoryAdjEndTimeMillis
+                            - onDiskAndInMemoryOffsetMillis, 0);
+                    mPersistence.collectHistoricalOpsDLocked(result, uid, packageName,
+                            attributionTag,
+                            opNames, filter, onDiskAdjBeginTimeMillis, onDiskAdjEndTimeMillis,
+                            flags);
+                }
+            }
+        }
+        // Rebase the result time to be since epoch.
+        result.setBeginAndEndTime(beginTimeMillis, endTimeMillis);
+
+        // Send back the result.
+        payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, result);
+        callback.sendResult(payload);
     }
 
     void incrementOpAccessedCount(int op, int uid, @NonNull String packageName,
@@ -692,6 +718,7 @@
             }
             persistPendingHistory(pendingWrites);
         }
+        mDiscreteRegistry.writeAndClearAccessHistory();
     }
 
     private void persistPendingHistory(@NonNull List<HistoricalOps> pendingWrites) {
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 5076007..088249e 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -52,6 +52,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Slog;
@@ -59,9 +60,9 @@
 import android.view.autofill.AutofillManagerInternal;
 import android.widget.Toast;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
-import com.android.server.SystemService.TargetUser;
 import com.android.server.UiThread;
 import com.android.server.contentcapture.ContentCaptureManagerInternal;
 import com.android.server.uri.UriGrantsManagerInternal;
@@ -164,6 +165,10 @@
     private static final boolean IS_EMULATOR =
         SystemProperties.getBoolean("ro.kernel.qemu", false);
 
+    // DeviceConfig properties
+    private static final String PROPERTY_SHOW_ACCESS_NOTIFICATIONS = "show_access_notifications";
+    private static final boolean DEFAULT_SHOW_ACCESS_NOTIFICATIONS = true;
+
     private final ActivityManagerInternal mAmInternal;
     private final IUriGrantsManager mUgm;
     private final UriGrantsManagerInternal mUgmInternal;
@@ -177,8 +182,14 @@
     private HostClipboardMonitor mHostClipboardMonitor = null;
     private Thread mHostMonitorThread = null;
 
+    @GuardedBy("mLock")
     private final SparseArray<PerUserClipboard> mClipboards = new SparseArray<>();
 
+    @GuardedBy("mLock")
+    private boolean mShowAccessNotifications = DEFAULT_SHOW_ACCESS_NOTIFICATIONS;
+
+    private final Object mLock = new Object();
+
     /**
      * Instantiates the clipboard.
      */
@@ -205,15 +216,19 @@
                             new ClipData("host clipboard",
                                          new String[]{"text/plain"},
                                          new ClipData.Item(contents));
-                        synchronized(mClipboards) {
+                        synchronized (mLock) {
                             setPrimaryClipInternal(getClipboard(0), clip,
-                                    android.os.Process.SYSTEM_UID);
+                                    android.os.Process.SYSTEM_UID, null);
                         }
                     }
                 });
             mHostMonitorThread = new Thread(mHostClipboardMonitor);
             mHostMonitorThread.start();
         }
+
+        updateConfig();
+        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_CLIPBOARD,
+                getContext().getMainExecutor(), properties -> updateConfig());
     }
 
     @Override
@@ -223,11 +238,18 @@
 
     @Override
     public void onUserStopped(@NonNull TargetUser user) {
-        synchronized (mClipboards) {
+        synchronized (mLock) {
             mClipboards.remove(user.getUserIdentifier());
         }
     }
 
+    private void updateConfig() {
+        synchronized (mLock) {
+            mShowAccessNotifications = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_CLIPBOARD,
+                    PROPERTY_SHOW_ACCESS_NOTIFICATIONS, DEFAULT_SHOW_ACCESS_NOTIFICATIONS);
+        }
+    }
+
     private class ListenerInfo {
         final int mUid;
         final String mPackageName;
@@ -247,6 +269,8 @@
         ClipData primaryClip;
         /** UID that set {@link #primaryClip}. */
         int primaryClipUid = android.os.Process.NOBODY_UID;
+        /** Package of the app that set {@link #primaryClip}. */
+        String mPrimaryClipPackage;
 
         final HashSet<String> activePermissionOwners
                 = new HashSet<String>();
@@ -365,7 +389,7 @@
                     return;
                 }
                 checkDataOwnerLocked(clip, intendingUid);
-                setPrimaryClipInternal(clip, intendingUid);
+                setPrimaryClipInternal(clip, intendingUid, callingPackage);
             }
         }
 
@@ -378,7 +402,7 @@
                         intendingUid, intendingUserId)) {
                     return;
                 }
-                setPrimaryClipInternal(null, intendingUid);
+                setPrimaryClipInternal(null, intendingUid, callingPackage);
             }
         }
 
@@ -471,7 +495,7 @@
     };
 
     private PerUserClipboard getClipboard(@UserIdInt int userId) {
-        synchronized (mClipboards) {
+        synchronized (mLock) {
             PerUserClipboard puc = mClipboards.get(userId);
             if (puc == null) {
                 puc = new PerUserClipboard(userId);
@@ -509,6 +533,11 @@
     }
 
     void setPrimaryClipInternal(@Nullable ClipData clip, int uid) {
+        setPrimaryClipInternal(clip, uid, null);
+    }
+
+    private void setPrimaryClipInternal(
+            @Nullable ClipData clip, int uid, @Nullable String sourcePackage) {
         // Push clipboard to host, if any
         if (mHostClipboardMonitor != null) {
             if (clip == null) {
@@ -524,7 +553,7 @@
 
         // Update this user
         final int userId = UserHandle.getUserId(uid);
-        setPrimaryClipInternal(getClipboard(userId), clip, uid);
+        setPrimaryClipInternal(getClipboard(userId), clip, uid, sourcePackage);
 
         // Update related users
         List<UserInfo> related = getRelatedProfiles(userId);
@@ -558,7 +587,8 @@
                         final boolean canCopyIntoProfile = !hasRestriction(
                                 UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, id);
                         if (canCopyIntoProfile) {
-                            setPrimaryClipInternal(getClipboard(id), clip, uid);
+                            setPrimaryClipInternal(
+                                    getClipboard(id), clip, uid, sourcePackage);
                         }
                     }
                 }
@@ -568,6 +598,11 @@
 
     void setPrimaryClipInternal(PerUserClipboard clipboard, @Nullable ClipData clip,
             int uid) {
+        setPrimaryClipInternal(clipboard, clip, uid, null);
+    }
+
+    private void setPrimaryClipInternal(PerUserClipboard clipboard, @Nullable ClipData clip,
+            int uid, @Nullable String sourcePackage) {
         revokeUris(clipboard);
         clipboard.activePermissionOwners.clear();
         if (clip == null && clipboard.primaryClip == null) {
@@ -576,8 +611,10 @@
         clipboard.primaryClip = clip;
         if (clip != null) {
             clipboard.primaryClipUid = uid;
+            clipboard.mPrimaryClipPackage = sourcePackage;
         } else {
             clipboard.primaryClipUid = android.os.Process.NOBODY_UID;
+            clipboard.mPrimaryClipPackage = null;
         }
         if (clip != null) {
             final ClipDescription description = clip.getDescription();
@@ -835,9 +872,10 @@
         if (clipboard.primaryClip == null) {
             return;
         }
-        if (Settings.Global.getInt(getContext().getContentResolver(),
-                "clipboard_access_toast_enabled", 1) == 0) {
-            return;
+        synchronized (mLock) {
+            if (!mShowAccessNotifications) {
+                return;
+            }
         }
         // Don't notify if the app accessing the clipboard is the same as the current owner.
         if (UserHandle.isSameApp(uid, clipboard.primaryClipUid)) {
@@ -861,29 +899,34 @@
                 && mAutofillInternal.isAugmentedAutofillServiceForUser(uid, userId)) {
             return;
         }
-        // Load the labels for the calling app and the app that set the clipboard content.
-        final long ident = Binder.clearCallingIdentity();
+
+        // Retrieve the app label of the source of the clip data
+        CharSequence sourceAppLabel = null;
+        if (clipboard.mPrimaryClipPackage != null) {
+            try {
+                sourceAppLabel = mPm.getApplicationLabel(mPm.getApplicationInfoAsUser(
+                        clipboard.mPrimaryClipPackage, 0, userId));
+            } catch (PackageManager.NameNotFoundException e) {
+                // leave label as null
+            }
+        }
+
         try {
-            final IPackageManager pm = AppGlobals.getPackageManager();
+            CharSequence callingAppLabel = mPm.getApplicationLabel(
+                    mPm.getApplicationInfoAsUser(callingPackage, 0, userId));
             String message;
-            final CharSequence callingLabel = mPm.getApplicationLabel(
-                    pm.getApplicationInfo(callingPackage, 0, userId));
-            final String[] packagesForUid = pm.getPackagesForUid(clipboard.primaryClipUid);
-            if (packagesForUid != null && packagesForUid.length > 0) {
-                final CharSequence clipLabel = mPm.getApplicationLabel(
-                        pm.getApplicationInfo(packagesForUid[0], 0,
-                                UserHandle.getUserId(clipboard.primaryClipUid)));
-                message = callingLabel + " pasted from " + clipLabel;
+            if (sourceAppLabel != null) {
+                message = callingAppLabel + " pasted from " + sourceAppLabel;
             } else {
-                message = callingLabel + " pasted from clipboard";
+                message = callingAppLabel + " pasted from clipboard";
             }
             Slog.i(TAG, message);
-            Toast.makeText(getContext(), UiThread.get().getLooper(), message, Toast.LENGTH_SHORT)
-                    .show();
-        } catch (RemoteException e) {
-            /* ignore */
-        } finally {
-            Binder.restoreCallingIdentity(ident);
+            Binder.withCleanCallingIdentity(() ->
+                    Toast.makeText(getContext(), UiThread.get().getLooper(), message,
+                            Toast.LENGTH_SHORT)
+                            .show());
+        } catch (PackageManager.NameNotFoundException e) {
+            // do nothing
         }
     }
 }
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index df83df9..5cf478a 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -80,6 +80,15 @@
     }
 
     /**
+     * @param change an object generated by services/core/xsd/platform-compat-config.xsd
+     */
+    public CompatChange(Change change) {
+        this(change.getId(), change.getName(), change.getEnableAfterTargetSdk(),
+                change.getEnableSinceTargetSdk(), change.getDisabled(), change.getLoggingOnly(),
+                change.getDescription(), change.getOverridable());
+    }
+
+    /**
      * @param changeId Unique ID for the change. See {@link android.compat.Compatibility}.
      * @param name Short descriptive name.
      * @param enableAfterTargetSdk {@code targetSdkVersion} restriction. See {@link EnabledAfter};
@@ -93,15 +102,10 @@
             boolean overridable) {
         super(changeId, name, enableAfterTargetSdk, enableSinceTargetSdk, disabled, loggingOnly,
               description, overridable);
-    }
 
-    /**
-     * @param change an object generated by services/core/xsd/platform-compat-config.xsd
-     */
-    public CompatChange(Change change) {
-        super(change.getId(), change.getName(), change.getEnableAfterTargetSdk(),
-                change.getEnableSinceTargetSdk(), change.getDisabled(), change.getLoggingOnly(),
-                change.getDescription(), change.getOverridable());
+        // Initialize override maps.
+        mEvaluatedOverrides = new HashMap<>();
+        mRawOverrides = new HashMap<>();
     }
 
     void registerListener(ChangeListener listener) {
@@ -127,18 +131,13 @@
             throw new IllegalArgumentException(
                     "Can't add overrides for a logging only change " + toString());
         }
-        if (mEvaluatedOverrides == null) {
-            mEvaluatedOverrides = new HashMap<>();
-        }
         mEvaluatedOverrides.put(pname, enabled);
         notifyListener(pname);
     }
 
     private void removePackageOverrideInternal(String pname) {
-        if (mEvaluatedOverrides != null) {
-            if (mEvaluatedOverrides.remove(pname) != null) {
-                notifyListener(pname);
-            }
+        if (mEvaluatedOverrides.remove(pname) != null) {
+            notifyListener(pname);
         }
     }
 
@@ -157,9 +156,6 @@
             throw new IllegalArgumentException(
                     "Can't add overrides for a logging only change " + toString());
         }
-        if (mRawOverrides == null) {
-            mRawOverrides = new HashMap<>();
-        }
         mRawOverrides.put(packageName, override);
         recheckOverride(packageName, allowedState, context);
     }
@@ -212,7 +208,7 @@
     }
 
     boolean hasPackageOverride(String pname) {
-        return mRawOverrides != null && mRawOverrides.containsKey(pname);
+        return mRawOverrides.containsKey(pname);
     }
     /**
      * Remove any package override for the given package name, restoring the default behaviour.
@@ -223,7 +219,7 @@
      */
     boolean removePackageOverride(String pname, OverrideAllowedState allowedState,
             Context context) {
-        if (mRawOverrides != null && (mRawOverrides.remove(pname) != null)) {
+        if (mRawOverrides.remove(pname) != null) {
             recheckOverride(pname, allowedState, context);
             return true;
         }
@@ -241,7 +237,7 @@
         if (app == null) {
             return defaultValue();
         }
-        if (mEvaluatedOverrides != null && mEvaluatedOverrides.containsKey(app.packageName)) {
+        if (mEvaluatedOverrides.containsKey(app.packageName)) {
             return mEvaluatedOverrides.get(app.packageName);
         }
         if (getDisabled()) {
@@ -289,7 +285,7 @@
      * @return true if there is such override
      */
     private boolean hasOverride(String packageName) {
-        return mEvaluatedOverrides != null && mEvaluatedOverrides.containsKey(packageName);
+        return mEvaluatedOverrides.containsKey(packageName);
     }
 
     /**
@@ -298,20 +294,15 @@
      * @return true if there is such a deferred override
      */
     private boolean hasRawOverride(String packageName) {
-        return mRawOverrides != null && mRawOverrides.containsKey(packageName);
+        return mRawOverrides.containsKey(packageName);
+    }
+
+    void clearOverrides() {
+        mRawOverrides.clear();
+        mEvaluatedOverrides.clear();
     }
 
     void loadOverrides(ChangeOverrides changeOverrides) {
-        if (mRawOverrides == null) {
-            mRawOverrides = new HashMap<>();
-        }
-        mRawOverrides.clear();
-
-        if (mEvaluatedOverrides == null) {
-            mEvaluatedOverrides = new HashMap<>();
-        }
-        mEvaluatedOverrides.clear();
-
         // Load deferred overrides for backwards compatibility
         if (changeOverrides.getDeferred() != null) {
             for (OverrideValue override : changeOverrides.getDeferred().getOverrideValue()) {
@@ -345,34 +336,30 @@
     }
 
     ChangeOverrides saveOverrides() {
-        if (mRawOverrides == null || mRawOverrides.isEmpty()) {
+        if (mRawOverrides.isEmpty()) {
             return null;
         }
         ChangeOverrides changeOverrides = new ChangeOverrides();
         changeOverrides.setChangeId(getId());
         ChangeOverrides.Raw rawOverrides = new ChangeOverrides.Raw();
         List<RawOverrideValue> rawList = rawOverrides.getRawOverrideValue();
-        if (mRawOverrides != null) {
-            for (Map.Entry<String, PackageOverride> entry : mRawOverrides.entrySet()) {
-                RawOverrideValue override = new RawOverrideValue();
-                override.setPackageName(entry.getKey());
-                override.setMinVersionCode(entry.getValue().getMinVersionCode());
-                override.setMaxVersionCode(entry.getValue().getMaxVersionCode());
-                override.setEnabled(entry.getValue().getEnabled());
-                rawList.add(override);
-            }
+        for (Map.Entry<String, PackageOverride> entry : mRawOverrides.entrySet()) {
+            RawOverrideValue override = new RawOverrideValue();
+            override.setPackageName(entry.getKey());
+            override.setMinVersionCode(entry.getValue().getMinVersionCode());
+            override.setMaxVersionCode(entry.getValue().getMaxVersionCode());
+            override.setEnabled(entry.getValue().getEnabled());
+            rawList.add(override);
         }
         changeOverrides.setRaw(rawOverrides);
 
         ChangeOverrides.Validated validatedOverrides = new ChangeOverrides.Validated();
         List<OverrideValue> validatedList = validatedOverrides.getOverrideValue();
-        if (mEvaluatedOverrides != null) {
-            for (Map.Entry<String, Boolean> entry : mEvaluatedOverrides.entrySet()) {
-                OverrideValue override = new OverrideValue();
-                override.setPackageName(entry.getKey());
-                override.setEnabled(entry.getValue());
-                validatedList.add(override);
-            }
+        for (Map.Entry<String, Boolean> entry : mEvaluatedOverrides.entrySet()) {
+            OverrideValue override = new OverrideValue();
+            override.setPackageName(entry.getKey());
+            override.setEnabled(entry.getValue());
+            validatedList.add(override);
         }
         changeOverrides.setValidated(validatedOverrides);
         return changeOverrides;
@@ -394,10 +381,10 @@
         if (getLoggingOnly()) {
             sb.append("; loggingOnly");
         }
-        if (mEvaluatedOverrides != null && mEvaluatedOverrides.size() > 0) {
+        if (!mEvaluatedOverrides.isEmpty()) {
             sb.append("; packageOverrides=").append(mEvaluatedOverrides);
         }
-        if (mRawOverrides != null && mRawOverrides.size() > 0) {
+        if (!mRawOverrides.isEmpty()) {
             sb.append("; rawOverrides=").append(mRawOverrides);
         }
         if (getOverridable()) {
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 422991e..2c053b4 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -50,6 +50,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -66,6 +67,7 @@
 
     private static final String TAG = "CompatConfig";
     private static final String APP_COMPAT_DATA_DIR = "/data/misc/appcompat";
+    private static final String STATIC_OVERRIDES_PRODUCT_DIR = "/product/etc/appcompat";
     private static final String OVERRIDES_FILE = "compat_framework_overrides.xml";
 
     @GuardedBy("mChanges")
@@ -93,8 +95,7 @@
             config.initConfigFromLib(Environment.buildPath(
                     apex.apexDirectory, "etc", "compatconfig"));
         }
-        File overridesFile = new File(APP_COMPAT_DATA_DIR, OVERRIDES_FILE);
-        config.initOverrides(overridesFile);
+        config.initOverrides();
         config.invalidateCache();
         return config;
     }
@@ -524,10 +525,34 @@
         }
     }
 
-    void initOverrides(File overridesFile) {
+    private void initOverrides() {
+        initOverrides(new File(APP_COMPAT_DATA_DIR, OVERRIDES_FILE),
+                new File(STATIC_OVERRIDES_PRODUCT_DIR, OVERRIDES_FILE));
+    }
+
+    @VisibleForTesting
+    void initOverrides(File dynamicOverridesFile, File staticOverridesFile) {
+        // Clear overrides from all changes before loading.
+        synchronized (mChanges) {
+            for (int i = 0; i < mChanges.size(); ++i) {
+                mChanges.valueAt(i).clearOverrides();
+            }
+        }
+
+        loadOverrides(staticOverridesFile);
+
+        mOverridesFile = dynamicOverridesFile;
+        loadOverrides(dynamicOverridesFile);
+
+        if (staticOverridesFile.exists()) {
+            // Only save overrides if there is a static overrides file.
+            saveOverrides();
+        }
+    }
+
+    private void loadOverrides(File overridesFile) {
         if (!overridesFile.exists()) {
-            mOverridesFile = overridesFile;
-            // There have not been any overrides added yet.
+            // Overrides file doesn't exist.
             return;
         }
 
@@ -547,7 +572,6 @@
             Slog.w(TAG, "Error processing " + overridesFile + " " + e.toString());
             return;
         }
-        mOverridesFile = overridesFile;
     }
 
     /**
@@ -595,17 +619,23 @@
      * Rechecks all the existing overrides for a package.
      */
     void recheckOverrides(String packageName) {
+        // Local cache of compat changes. Holding a lock on mChanges for the whole duration of the
+        // method will cause a deadlock.
+        List<CompatChange> changes;
         synchronized (mChanges) {
-            boolean shouldInvalidateCache = false;
+            changes = new ArrayList<>(mChanges.size());
             for (int idx = 0; idx < mChanges.size(); ++idx) {
-                CompatChange c = mChanges.valueAt(idx);
-                OverrideAllowedState allowedState =
-                        mOverrideValidator.getOverrideAllowedState(c.getId(), packageName);
-                shouldInvalidateCache |= c.recheckOverride(packageName, allowedState, mContext);
+                changes.add(mChanges.valueAt(idx));
             }
-            if (shouldInvalidateCache) {
-                invalidateCache();
-            }
+        }
+        boolean shouldInvalidateCache = false;
+        for (CompatChange c: changes) {
+            OverrideAllowedState allowedState =
+                    mOverrideValidator.getOverrideAllowedState(c.getId(), packageName);
+            shouldInvalidateCache |= c.recheckOverride(packageName, allowedState, mContext);
+        }
+        if (shouldInvalidateCache) {
+            invalidateCache();
         }
     }
 
diff --git a/services/core/java/com/android/server/connectivity/DataConnectionStats.java b/services/core/java/com/android/server/connectivity/DataConnectionStats.java
index fbd089c..15f43a0 100644
--- a/services/core/java/com/android/server/connectivity/DataConnectionStats.java
+++ b/services/core/java/com/android/server/connectivity/DataConnectionStats.java
@@ -52,6 +52,7 @@
     private SignalStrength mSignalStrength;
     private ServiceState mServiceState;
     private int mDataState = TelephonyManager.DATA_DISCONNECTED;
+    private int mNrState = NetworkRegistrationInfo.NR_STATE_NONE;
 
     public DataConnectionStats(Context context, Handler listenerHandler) {
         mContext = context;
@@ -99,7 +100,7 @@
                 : regInfo.getAccessNetworkTechnology();
         // If the device is in NSA NR connection the networkType will report as LTE.
         // For cell dwell rate metrics, this should report NR instead.
-        if (regInfo != null && regInfo.getNrState() == NetworkRegistrationInfo.NR_STATE_CONNECTED) {
+        if (mNrState == NetworkRegistrationInfo.NR_STATE_CONNECTED) {
             networkType = TelephonyManager.NETWORK_TYPE_NR;
         }
         if (DEBUG) Log.d(TAG, String.format("Noting data connection for network type %s: %svisible",
@@ -171,6 +172,7 @@
         @Override
         public void onServiceStateChanged(ServiceState state) {
             mServiceState = state;
+            mNrState = state.getNrState();
             notePhoneDataConnectionState();
         }
 
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index 43d9ade..4f6b530 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -19,6 +19,8 @@
 import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE_FALLBACK;
 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
+import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE;
+import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS;
 import static android.provider.Settings.Global.DNS_RESOLVER_MAX_SAMPLES;
 import static android.provider.Settings.Global.DNS_RESOLVER_MIN_SAMPLES;
 import static android.provider.Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS;
@@ -147,17 +149,18 @@
     }
 
     public static class PrivateDnsValidationUpdate {
-        final public int netId;
-        final public InetAddress ipAddress;
-        final public String hostname;
-        final public boolean validated;
+        public final int netId;
+        public final InetAddress ipAddress;
+        public final String hostname;
+        // Refer to IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_*.
+        public final int validationResult;
 
         public PrivateDnsValidationUpdate(int netId, InetAddress ipAddress,
-                String hostname, boolean validated) {
+                String hostname, int validationResult) {
             this.netId = netId;
             this.ipAddress = ipAddress;
             this.hostname = hostname;
-            this.validated = validated;
+            this.validationResult = validationResult;
         }
     }
 
@@ -216,10 +219,13 @@
             if (!mValidationMap.containsKey(p)) {
                 return;
             }
-            if (update.validated) {
+            if (update.validationResult == VALIDATION_RESULT_SUCCESS) {
                 mValidationMap.put(p, ValidationStatus.SUCCEEDED);
-            } else {
+            } else if (update.validationResult == VALIDATION_RESULT_FAILURE) {
                 mValidationMap.put(p, ValidationStatus.FAILED);
+            } else {
+                Log.e(TAG, "Unknown private dns validation operation="
+                        + update.validationResult);
             }
         }
 
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 34d9ccc..7b20ded 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -57,8 +57,8 @@
 import android.util.Pair;
 
 import com.android.internal.R;
-import com.android.internal.util.HexDump;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.net.module.util.HexDump;
 import com.android.net.module.util.IpUtils;
 
 import java.io.FileDescriptor;
diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
index 21ef356..4ecc759 100644
--- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
+++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
@@ -26,6 +26,7 @@
 import static android.net.NetworkPolicy.LIMIT_DISABLED;
 import static android.net.NetworkPolicy.WARNING_DISABLED;
 import static android.net.NetworkTemplate.NETWORK_TYPE_ALL;
+import static android.net.NetworkTemplate.OEM_MANAGED_ALL;
 import static android.provider.Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES;
 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
@@ -226,7 +227,7 @@
             mNetworkTemplate = new NetworkTemplate(
                     NetworkTemplate.MATCH_MOBILE, subscriberId, new String[] { subscriberId },
                     null, NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
-                    NetworkStats.DEFAULT_NETWORK_NO, NETWORK_TYPE_ALL);
+                    NetworkStats.DEFAULT_NETWORK_NO, NETWORK_TYPE_ALL, OEM_MANAGED_ALL);
             mUsageCallback = new UsageCallback() {
                 @Override
                 public void onThresholdReached(int networkType, String subscriberId) {
@@ -274,7 +275,8 @@
                     null /* networkId, unused for matching mobile networks */,
                     !nc.hasCapability(NET_CAPABILITY_NOT_ROAMING),
                     !nc.hasCapability(NET_CAPABILITY_NOT_METERED),
-                    false /* defaultNetwork, templates should have DEFAULT_NETWORK_ALL */);
+                    false /* defaultNetwork, templates should have DEFAULT_NETWORK_ALL */,
+                    OEM_MANAGED_ALL);
         }
 
         private long getRemainingDailyBudget(long limitBytes,
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 641287f..fa80b25 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -29,14 +29,12 @@
 import android.net.LinkProperties;
 import android.net.NetworkInfo;
 import android.net.RouteInfo;
-import android.os.INetworkManagementService;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.net.module.util.NetworkStackConstants;
-import com.android.server.net.BaseNetworkObserver;
 
 import java.net.Inet6Address;
 import java.util.Objects;
@@ -48,7 +46,7 @@
  *
  * @hide
  */
-public class Nat464Xlat extends BaseNetworkObserver {
+public class Nat464Xlat {
     private static final String TAG = Nat464Xlat.class.getSimpleName();
 
     // This must match the interface prefix in clatd.c.
@@ -70,7 +68,6 @@
 
     private final IDnsResolver mDnsResolver;
     private final INetd mNetd;
-    private final INetworkManagementService mNMService;
 
     // The network we're running on, and its type.
     private final NetworkAgentInfo mNetwork;
@@ -99,11 +96,9 @@
 
     private boolean mPrefixDiscoveryRunning;
 
-    public Nat464Xlat(NetworkAgentInfo nai, INetd netd, IDnsResolver dnsResolver,
-            INetworkManagementService nmService) {
+    public Nat464Xlat(NetworkAgentInfo nai, INetd netd, IDnsResolver dnsResolver) {
         mDnsResolver = dnsResolver;
         mNetd = netd;
-        mNMService = nmService;
         mNetwork = nai;
     }
 
@@ -174,13 +169,6 @@
      * and set internal state.
      */
     private void enterStartingState(String baseIface) {
-        try {
-            mNMService.registerObserver(this);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Can't register iface observer for clat on " + mNetwork.toShortString());
-            return;
-        }
-
         mNat64PrefixInUse = selectNat64Prefix();
         String addrStr = null;
         try {
@@ -216,11 +204,6 @@
      * Unregister as a base observer for the stacked interface, and clear internal state.
      */
     private void leaveStartedState() {
-        try {
-            mNMService.unregisterObserver(this);
-        } catch (RemoteException | IllegalStateException e) {
-            Log.e(TAG, "Error unregistering clatd observer on " + mBaseIface + ": " + e);
-        }
         mNat64PrefixInUse = null;
         mIface = null;
         mBaseIface = null;
@@ -507,12 +490,10 @@
         stop();
     }
 
-    @Override
     public void interfaceLinkStateChanged(String iface, boolean up) {
         mNetwork.handler().post(() -> { handleInterfaceLinkStateChanged(iface, up); });
     }
 
-    @Override
     public void interfaceRemoved(String iface) {
         mNetwork.handler().post(() -> handleInterfaceRemoved(iface));
     }
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 4cf5274..cac6cab 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -43,7 +43,6 @@
 import android.net.TcpKeepalivePacketData;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.INetworkManagementService;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.telephony.data.EpsBearerQosSessionAttributes;
@@ -341,8 +340,8 @@
     public NetworkAgentInfo(INetworkAgent na, Network net, NetworkInfo info,
             @NonNull LinkProperties lp, @NonNull NetworkCapabilities nc, int score, Context context,
             Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
-            IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber,
-            int creatorUid, QosCallbackTracker qosCallbackTracker) {
+            IDnsResolver dnsResolver, int factorySerialNumber, int creatorUid,
+            QosCallbackTracker qosCallbackTracker) {
         Objects.requireNonNull(net);
         Objects.requireNonNull(info);
         Objects.requireNonNull(lp);
@@ -356,7 +355,7 @@
         linkProperties = lp;
         networkCapabilities = nc;
         mScore = score;
-        clatd = new Nat464Xlat(this, netd, dnsResolver, nms);
+        clatd = new Nat464Xlat(this, netd, dnsResolver);
         mConnService = connService;
         mContext = context;
         mHandler = handler;
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 01ac81fb..2e61ae1 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -22,6 +22,7 @@
 import static android.net.RouteInfo.RTN_THROW;
 import static android.net.RouteInfo.RTN_UNREACHABLE;
 import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN;
+import static android.os.PowerWhitelistManager.REASON_VPN;
 
 import static com.android.internal.util.Preconditions.checkArgument;
 import static com.android.internal.util.Preconditions.checkNotNull;
@@ -100,7 +101,12 @@
 import android.os.UserManager;
 import android.provider.Settings;
 import android.security.Credentials;
-import android.security.KeyStore;
+import android.security.KeyStore2;
+import android.security.keystore.AndroidKeyStoreProvider;
+import android.security.keystore.KeyProperties;
+import android.system.keystore2.Domain;
+import android.system.keystore2.KeyDescriptor;
+import android.system.keystore2.KeyPermission;
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
@@ -131,6 +137,12 @@
 import java.net.UnknownHostException;
 import java.nio.charset.StandardCharsets;
 import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -156,6 +168,7 @@
     private static final String TAG = "Vpn";
     private static final String VPN_PROVIDER_NAME_BASE = "VpnNetworkProvider:";
     private static final boolean LOGD = true;
+    private static final String ANDROID_KEYSTORE_PROVIDER = "AndroidKeyStore";
 
     // Length of time (in milliseconds) that an app hosting an always-on VPN is placed on
     // the device idle allowlist during service launch and VPN bootstrap.
@@ -215,6 +228,13 @@
     private final Ikev2SessionCreator mIkev2SessionCreator;
     private final UserManager mUserManager;
 
+    private final VpnProfileStore mVpnProfileStore;
+
+    @VisibleForTesting
+    VpnProfileStore getVpnProfileStore() {
+        return mVpnProfileStore;
+    }
+
     /**
      * Whether to keep the connection active after rebooting, or upgrading or reinstalling. This
      * only applies to {@link VpnService} connections.
@@ -392,24 +412,25 @@
     }
 
     public Vpn(Looper looper, Context context, INetworkManagementService netService, INetd netd,
-            @UserIdInt int userId, @NonNull KeyStore keyStore) {
-        this(looper, context, new Dependencies(), netService, netd, userId, keyStore,
+            @UserIdInt int userId, VpnProfileStore vpnProfileStore) {
+        this(looper, context, new Dependencies(), netService, netd, userId, vpnProfileStore,
                 new SystemServices(context), new Ikev2SessionCreator());
     }
 
     @VisibleForTesting
     public Vpn(Looper looper, Context context, Dependencies deps,
             INetworkManagementService netService, INetd netd, @UserIdInt int userId,
-            @NonNull KeyStore keyStore) {
-        this(looper, context, deps, netService, netd, userId, keyStore,
+            VpnProfileStore vpnProfileStore) {
+        this(looper, context, deps, netService, netd, userId, vpnProfileStore,
                 new SystemServices(context), new Ikev2SessionCreator());
     }
 
     @VisibleForTesting
     protected Vpn(Looper looper, Context context, Dependencies deps,
             INetworkManagementService netService, INetd netd,
-            int userId, @NonNull KeyStore keyStore, SystemServices systemServices,
+            int userId, VpnProfileStore vpnProfileStore, SystemServices systemServices,
             Ikev2SessionCreator ikev2SessionCreator) {
+        mVpnProfileStore = vpnProfileStore;
         mContext = context;
         mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
         mUserIdContext = context.createContextAsUser(UserHandle.of(userId), 0 /* flags */);
@@ -445,7 +466,7 @@
         mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
         mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE));
 
-        loadAlwaysOnPackage(keyStore);
+        loadAlwaysOnPackage();
     }
 
     /**
@@ -566,11 +587,9 @@
      * </ul>
      *
      * @param packageName the canonical package name of the VPN app
-     * @param keyStore the keystore instance to use for checking if the app has a Platform VPN
-     *     profile installed.
      * @return {@code true} if and only if the VPN app exists and supports always-on mode
      */
-    public boolean isAlwaysOnPackageSupported(String packageName, @NonNull KeyStore keyStore) {
+    public boolean isAlwaysOnPackageSupported(String packageName) {
         enforceSettingsPermission();
 
         if (packageName == null) {
@@ -579,7 +598,7 @@
 
         final long oldId = Binder.clearCallingIdentity();
         try {
-            if (getVpnProfilePrivileged(packageName, keyStore) != null) {
+            if (getVpnProfilePrivileged(packageName) != null) {
                 return true;
             }
         } finally {
@@ -631,17 +650,15 @@
      * @param packageName the package to designate as always-on VPN supplier.
      * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting.
      * @param lockdownAllowlist packages to be allowed from lockdown.
-     * @param keyStore the Keystore instance to use for checking of PlatformVpnProfile(s)
      * @return {@code true} if the package has been set as always-on, {@code false} otherwise.
      */
     public synchronized boolean setAlwaysOnPackage(
             @Nullable String packageName,
             boolean lockdown,
-            @Nullable List<String> lockdownAllowlist,
-            @NonNull KeyStore keyStore) {
+            @Nullable List<String> lockdownAllowlist) {
         enforceControlPermissionOrInternalCaller();
 
-        if (setAlwaysOnPackageInternal(packageName, lockdown, lockdownAllowlist, keyStore)) {
+        if (setAlwaysOnPackageInternal(packageName, lockdown, lockdownAllowlist)) {
             saveAlwaysOnPackage();
             return true;
         }
@@ -658,13 +675,12 @@
      * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting.
      * @param lockdownAllowlist packages to be allowed to bypass lockdown. This is only used if
      *     {@code lockdown} is {@code true}. Packages must not contain commas.
-     * @param keyStore the system keystore instance to check for profiles
      * @return {@code true} if the package has been set as always-on, {@code false} otherwise.
      */
     @GuardedBy("this")
     private boolean setAlwaysOnPackageInternal(
             @Nullable String packageName, boolean lockdown,
-            @Nullable List<String> lockdownAllowlist, @NonNull KeyStore keyStore) {
+            @Nullable List<String> lockdownAllowlist) {
         if (VpnConfig.LEGACY_VPN.equals(packageName)) {
             Log.w(TAG, "Not setting legacy VPN \"" + packageName + "\" as always-on.");
             return false;
@@ -683,7 +699,7 @@
             final VpnProfile profile;
             final long oldId = Binder.clearCallingIdentity();
             try {
-                profile = getVpnProfilePrivileged(packageName, keyStore);
+                profile = getVpnProfilePrivileged(packageName);
             } finally {
                 Binder.restoreCallingIdentity(oldId);
             }
@@ -758,7 +774,7 @@
 
     /** Load the always-on package and lockdown config from Settings. */
     @GuardedBy("this")
-    private void loadAlwaysOnPackage(@NonNull KeyStore keyStore) {
+    private void loadAlwaysOnPackage() {
         final long token = Binder.clearCallingIdentity();
         try {
             final String alwaysOnPackage = mSystemServices.settingsSecureGetStringForUser(
@@ -770,7 +786,7 @@
             final List<String> allowedPackages = TextUtils.isEmpty(allowlistString)
                     ? Collections.emptyList() : Arrays.asList(allowlistString.split(","));
             setAlwaysOnPackageInternal(
-                    alwaysOnPackage, alwaysOnLockdown, allowedPackages, keyStore);
+                    alwaysOnPackage, alwaysOnLockdown, allowedPackages);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -779,11 +795,10 @@
     /**
      * Starts the currently selected always-on VPN
      *
-     * @param keyStore the keyStore instance for looking up PlatformVpnProfile(s)
      * @return {@code true} if the service was started, the service was already connected, or there
      *     was no always-on VPN to start. {@code false} otherwise.
      */
-    public boolean startAlwaysOnVpn(@NonNull KeyStore keyStore) {
+    public boolean startAlwaysOnVpn() {
         final String alwaysOnPackage;
         synchronized (this) {
             alwaysOnPackage = getAlwaysOnPackage();
@@ -792,8 +807,8 @@
                 return true;
             }
             // Remove always-on VPN if it's not supported.
-            if (!isAlwaysOnPackageSupported(alwaysOnPackage, keyStore)) {
-                setAlwaysOnPackage(null, false, null, keyStore);
+            if (!isAlwaysOnPackageSupported(alwaysOnPackage)) {
+                setAlwaysOnPackage(null, false, null);
                 return false;
             }
             // Skip if the service is already established. This isn't bulletproof: it's not bound
@@ -807,10 +822,9 @@
         final long oldId = Binder.clearCallingIdentity();
         try {
             // Prefer VPN profiles, if any exist.
-            VpnProfile profile = getVpnProfilePrivileged(alwaysOnPackage, keyStore);
+            VpnProfile profile = getVpnProfilePrivileged(alwaysOnPackage);
             if (profile != null) {
-                startVpnProfilePrivileged(profile, alwaysOnPackage,
-                        null /* keyStore for private key retrieval - unneeded */);
+                startVpnProfilePrivileged(profile, alwaysOnPackage);
 
                 // If the above startVpnProfilePrivileged() call returns, the Ikev2VpnProfile was
                 // correctly parsed, and the VPN has started running in a different thread. The only
@@ -825,7 +839,8 @@
             // a short time, so we can bootstrap the VPN service.
             DeviceIdleInternal idleController = mDeps.getDeviceIdleInternal();
             idleController.addPowerSaveTempWhitelistApp(Process.myUid(), alwaysOnPackage,
-                    VPN_LAUNCH_IDLE_ALLOWLIST_DURATION_MS, mUserId, false, "vpn");
+                    VPN_LAUNCH_IDLE_ALLOWLIST_DURATION_MS, mUserId, false, REASON_VPN,
+                    "vpn");
 
             // Start the VPN service declared in the app's manifest.
             Intent serviceIntent = new Intent(VpnConfig.SERVICE_INTERFACE);
@@ -2011,27 +2026,83 @@
      * secondary thread to perform connection work, returning quickly.
      *
      * Should only be called to respond to Binder requests as this enforces caller permission. Use
-     * {@link #startLegacyVpnPrivileged(VpnProfile, KeyStore, Network, LinkProperties)} to skip the
+     * {@link #startLegacyVpnPrivileged(VpnProfile, Network, LinkProperties)} to skip the
      * permission check only when the caller is trusted (or the call is initiated by the system).
      */
-    public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, @Nullable Network underlying,
+    public void startLegacyVpn(VpnProfile profile, @Nullable Network underlying,
             LinkProperties egress) {
         enforceControlPermission();
         final long token = Binder.clearCallingIdentity();
         try {
-            startLegacyVpnPrivileged(profile, keyStore, underlying, egress);
+            startLegacyVpnPrivileged(profile, underlying, egress);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
     }
 
+    private String makeKeystoreEngineGrantString(String alias) {
+        if (alias == null) {
+            return null;
+        }
+        // If Keystore 2.0 is not enabled the legacy private key prefix is used.
+        if (!AndroidKeyStoreProvider.isKeystore2Enabled()) {
+            return Credentials.USER_PRIVATE_KEY + alias;
+        }
+        final KeyStore2 keystore2 = KeyStore2.getInstance();
+
+        KeyDescriptor key = new KeyDescriptor();
+        key.domain = Domain.APP;
+        key.nspace = KeyProperties.NAMESPACE_APPLICATION;
+        key.alias = alias;
+        key.blob = null;
+
+        final int grantAccessVector = KeyPermission.USE | KeyPermission.GET_INFO;
+
+        try {
+            // The native vpn daemon is running as VPN_UID. This tells Keystore 2.0
+            // to allow a process running with this UID to access the key designated by
+            // the KeyDescriptor `key`. `grant` returns a new KeyDescriptor with a grant
+            // identifier. This identifier needs to be communicated to the vpn daemon.
+            key = keystore2.grant(key, android.os.Process.VPN_UID, grantAccessVector);
+        } catch (android.security.KeyStoreException e) {
+            Log.e(TAG, "Failed to get grant for keystore key.", e);
+            throw new IllegalStateException("Failed to get grant for keystore key.", e);
+        }
+
+        // Turn the grant identifier into a string as understood by the keystore boringssl engine
+        // in system/security/keystore-engine.
+        return KeyStore2.makeKeystoreEngineGrantString(key.nspace);
+    }
+
+    private String getCaCertificateFromKeystoreAsPem(@NonNull KeyStore keystore,
+            @NonNull String alias)
+            throws KeyStoreException, IOException, CertificateEncodingException {
+        if (keystore.isCertificateEntry(alias)) {
+            final Certificate cert = keystore.getCertificate(alias);
+            if (cert == null) return null;
+            return new String(Credentials.convertToPem(cert), StandardCharsets.UTF_8);
+        } else {
+            final Certificate[] certs = keystore.getCertificateChain(alias);
+            // If there is none or one entry it means there is no CA entry associated with this
+            // alias.
+            if (certs == null || certs.length <= 1) {
+                return null;
+            }
+            // If this is not a (pure) certificate entry, then there is a user certificate which
+            // will be included at the beginning of the certificate chain. But the caller of this
+            // function does not expect this certificate to be included, so we cut it off.
+            return new String(Credentials.convertToPem(
+                    Arrays.copyOfRange(certs, 1, certs.length)), StandardCharsets.UTF_8);
+        }
+    }
+
     /**
-     * Like {@link #startLegacyVpn(VpnProfile, KeyStore, Network, LinkProperties)}, but does not
+     * Like {@link #startLegacyVpn(VpnProfile, Network, LinkProperties)}, but does not
      * check permissions under the assumption that the caller is the system.
      *
      * Callers are responsible for checking permissions if needed.
      */
-    public void startLegacyVpnPrivileged(VpnProfile profile, KeyStore keyStore,
+    public void startLegacyVpnPrivileged(VpnProfile profile,
             @Nullable Network underlying, @NonNull LinkProperties egress) {
         UserInfo user = mUserManager.getUserInfo(mUserId);
         if (user.isRestricted() || mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN,
@@ -2048,18 +2119,27 @@
         String userCert = "";
         String caCert = "";
         String serverCert = "";
-        if (!profile.ipsecUserCert.isEmpty()) {
-            privateKey = Credentials.USER_PRIVATE_KEY + profile.ipsecUserCert;
-            byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecUserCert);
-            userCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8);
-        }
-        if (!profile.ipsecCaCert.isEmpty()) {
-            byte[] value = keyStore.get(Credentials.CA_CERTIFICATE + profile.ipsecCaCert);
-            caCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8);
-        }
-        if (!profile.ipsecServerCert.isEmpty()) {
-            byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecServerCert);
-            serverCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8);
+
+        try {
+            final KeyStore keystore = KeyStore.getInstance(ANDROID_KEYSTORE_PROVIDER);
+            keystore.load(null);
+            if (!profile.ipsecUserCert.isEmpty()) {
+                privateKey = profile.ipsecUserCert;
+                final Certificate cert = keystore.getCertificate(profile.ipsecUserCert);
+                userCert = (cert == null) ? null
+                         : new String(Credentials.convertToPem(cert), StandardCharsets.UTF_8);
+            }
+            if (!profile.ipsecCaCert.isEmpty()) {
+                caCert = getCaCertificateFromKeystoreAsPem(keystore, profile.ipsecCaCert);
+            }
+            if (!profile.ipsecServerCert.isEmpty()) {
+                final Certificate cert = keystore.getCertificate(profile.ipsecServerCert);
+                serverCert = (cert == null) ? null
+                        : new String(Credentials.convertToPem(cert), StandardCharsets.UTF_8);
+            }
+        } catch (CertificateException | KeyStoreException | IOException
+                | NoSuchAlgorithmException e) {
+            throw new IllegalStateException("Failed to load credentials from AndroidKeyStore", e);
         }
         if (userCert == null || caCert == null || serverCert == null) {
             throw new IllegalStateException("Cannot load credentials");
@@ -2080,7 +2160,7 @@
 
                 // Start VPN profile
                 profile.setAllowedAlgorithms(Ikev2VpnProfile.DEFAULT_ALGORITHMS);
-                startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN, keyStore);
+                startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN);
                 return;
             case VpnProfile.TYPE_IKEV2_IPSEC_PSK:
                 // Ikev2VpnProfiles expect a base64-encoded preshared key.
@@ -2089,7 +2169,7 @@
 
                 // Start VPN profile
                 profile.setAllowedAlgorithms(Ikev2VpnProfile.DEFAULT_ALGORITHMS);
-                startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN, keyStore);
+                startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN);
                 return;
             case VpnProfile.TYPE_L2TP_IPSEC_PSK:
                 racoon = new String[] {
@@ -2099,8 +2179,8 @@
                 break;
             case VpnProfile.TYPE_L2TP_IPSEC_RSA:
                 racoon = new String[] {
-                    iface, profile.server, "udprsa", privateKey, userCert,
-                    caCert, serverCert, "1701",
+                    iface, profile.server, "udprsa", makeKeystoreEngineGrantString(privateKey),
+                    userCert, caCert, serverCert, "1701",
                 };
                 break;
             case VpnProfile.TYPE_IPSEC_XAUTH_PSK:
@@ -2111,8 +2191,8 @@
                 break;
             case VpnProfile.TYPE_IPSEC_XAUTH_RSA:
                 racoon = new String[] {
-                    iface, profile.server, "xauthrsa", privateKey, userCert,
-                    caCert, serverCert, profile.username, profile.password, "", gateway,
+                    iface, profile.server, "xauthrsa", makeKeystoreEngineGrantString(privateKey),
+                    userCert, caCert, serverCert, profile.username, profile.password, "", gateway,
                 };
                 break;
             case VpnProfile.TYPE_IPSEC_HYBRID_RSA:
@@ -3047,14 +3127,12 @@
      *
      * @param packageName the package name of the app provisioning this profile
      * @param profile the profile to be stored and provisioned
-     * @param keyStore the System keystore instance to save VPN profiles
      * @returns whether or not the app has already been granted user consent
      */
     public synchronized boolean provisionVpnProfile(
-            @NonNull String packageName, @NonNull VpnProfile profile, @NonNull KeyStore keyStore) {
+            @NonNull String packageName, @NonNull VpnProfile profile) {
         checkNotNull(packageName, "No package name provided");
         checkNotNull(profile, "No profile provided");
-        checkNotNull(keyStore, "KeyStore missing");
 
         verifyCallingUidAndPackage(packageName);
         enforceNotRestrictedUser();
@@ -3073,11 +3151,9 @@
         // Permissions checked during startVpnProfile()
         Binder.withCleanCallingIdentity(
                 () -> {
-                    keyStore.put(
+                    getVpnProfileStore().put(
                             getProfileNameForPackage(packageName),
-                            encodedProfile,
-                            Process.SYSTEM_UID,
-                            0 /* flags */);
+                            encodedProfile);
                 });
 
         // TODO: if package has CONTROL_VPN, grant the ACTIVATE_PLATFORM_VPN appop.
@@ -3095,12 +3171,10 @@
      * Deletes an app-provisioned VPN profile.
      *
      * @param packageName the package name of the app provisioning this profile
-     * @param keyStore the System keystore instance to save VPN profiles
      */
     public synchronized void deleteVpnProfile(
-            @NonNull String packageName, @NonNull KeyStore keyStore) {
+            @NonNull String packageName) {
         checkNotNull(packageName, "No package name provided");
-        checkNotNull(keyStore, "KeyStore missing");
 
         verifyCallingUidAndPackage(packageName);
         enforceNotRestrictedUser();
@@ -3112,13 +3186,13 @@
                     if (isCurrentIkev2VpnLocked(packageName)) {
                         if (mAlwaysOn) {
                             // Will transitively call prepareInternal(VpnConfig.LEGACY_VPN).
-                            setAlwaysOnPackage(null, false, null, keyStore);
+                            setAlwaysOnPackage(null, false, null);
                         } else {
                             prepareInternal(VpnConfig.LEGACY_VPN);
                         }
                     }
 
-                    keyStore.delete(getProfileNameForPackage(packageName), Process.SYSTEM_UID);
+                    getVpnProfileStore().remove(getProfileNameForPackage(packageName));
                 });
     }
 
@@ -3130,13 +3204,13 @@
      */
     @VisibleForTesting
     @Nullable
-    VpnProfile getVpnProfilePrivileged(@NonNull String packageName, @NonNull KeyStore keyStore) {
+    VpnProfile getVpnProfilePrivileged(@NonNull String packageName) {
         if (!mDeps.isCallerSystem()) {
             Log.wtf(TAG, "getVpnProfilePrivileged called as non-System UID ");
             return null;
         }
 
-        final byte[] encoded = keyStore.get(getProfileNameForPackage(packageName));
+        final byte[] encoded = getVpnProfileStore().get(getProfileNameForPackage(packageName));
         if (encoded == null) return null;
 
         return VpnProfile.decode("" /* Key unused */, encoded);
@@ -3150,12 +3224,10 @@
      * will not match during appop checks.
      *
      * @param packageName the package name of the app provisioning this profile
-     * @param keyStore the System keystore instance to retrieve VPN profiles
      */
     public synchronized void startVpnProfile(
-            @NonNull String packageName, @NonNull KeyStore keyStore) {
+            @NonNull String packageName) {
         checkNotNull(packageName, "No package name provided");
-        checkNotNull(keyStore, "KeyStore missing");
 
         enforceNotRestrictedUser();
 
@@ -3166,18 +3238,17 @@
 
         Binder.withCleanCallingIdentity(
                 () -> {
-                    final VpnProfile profile = getVpnProfilePrivileged(packageName, keyStore);
+                    final VpnProfile profile = getVpnProfilePrivileged(packageName);
                     if (profile == null) {
                         throw new IllegalArgumentException("No profile found for " + packageName);
                     }
 
-                    startVpnProfilePrivileged(profile, packageName,
-                            null /* keyStore for private key retrieval - unneeded */);
+                    startVpnProfilePrivileged(profile, packageName);
                 });
     }
 
     private synchronized void startVpnProfilePrivileged(
-            @NonNull VpnProfile profile, @NonNull String packageName, @Nullable KeyStore keyStore) {
+            @NonNull VpnProfile profile, @NonNull String packageName) {
         // Make sure VPN is prepared. This method can be called by user apps via startVpnProfile(),
         // by the Setting app via startLegacyVpn(), or by ConnectivityService via
         // startAlwaysOnVpn(), so this is the common place to prepare the VPN. This also has the
@@ -3208,7 +3279,7 @@
                 case VpnProfile.TYPE_IKEV2_IPSEC_PSK:
                 case VpnProfile.TYPE_IKEV2_IPSEC_RSA:
                     mVpnRunner =
-                            new IkeV2VpnRunner(Ikev2VpnProfile.fromVpnProfile(profile, keyStore));
+                            new IkeV2VpnRunner(Ikev2VpnProfile.fromVpnProfile(profile));
                     mVpnRunner.start();
                     break;
                 default:
@@ -3216,7 +3287,7 @@
                     Log.d(TAG, "Unknown VPN profile type: " + profile.type);
                     break;
             }
-        } catch (IOException | GeneralSecurityException e) {
+        } catch (GeneralSecurityException e) {
             // Reset mConfig
             mConfig = null;
 
diff --git a/services/core/java/com/android/server/connectivity/VpnProfileStore.java b/services/core/java/com/android/server/connectivity/VpnProfileStore.java
new file mode 100644
index 0000000..2f8aebf
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/VpnProfileStore.java
@@ -0,0 +1,77 @@
+/*
+ * 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.connectivity;
+
+import android.annotation.NonNull;
+import android.security.LegacyVpnProfileStore;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Mockable indirection to the actual profile store.
+ * @hide
+ */
+public class VpnProfileStore {
+    /**
+     * Stores the profile under the alias in the profile database. Existing profiles by the
+     * same name will be replaced.
+     * @param alias The name of the profile
+     * @param profile The profile.
+     * @return true if the profile was successfully added. False otherwise.
+     * @hide
+     */
+    @VisibleForTesting
+    public boolean put(@NonNull String alias, @NonNull byte[] profile) {
+        return LegacyVpnProfileStore.put(alias, profile);
+    }
+
+    /**
+     * Retrieves a profile by the name alias from the profile database.
+     * @param alias Name of the profile to retrieve.
+     * @return The unstructured blob, that is the profile that was stored using
+     *         LegacyVpnProfileStore#put or with
+     *         android.security.Keystore.put(Credentials.VPN + alias).
+     *         Returns null if no profile was found.
+     * @hide
+     */
+    @VisibleForTesting
+    public byte[] get(@NonNull String alias) {
+        return LegacyVpnProfileStore.get(alias);
+    }
+
+    /**
+     * Removes a profile by the name alias from the profile database.
+     * @param alias Name of the profile to be removed.
+     * @return True if a profile was removed. False if no such profile was found.
+     * @hide
+     */
+    @VisibleForTesting
+    public boolean remove(@NonNull String alias) {
+        return LegacyVpnProfileStore.remove(alias);
+    }
+
+    /**
+     * Lists the vpn profiles stored in the database.
+     * @return An array of strings representing the aliases stored in the profile database.
+     *         The return value may be empty but never null.
+     * @hide
+     */
+    @VisibleForTesting
+    public @NonNull String[] list(@NonNull String prefix) {
+        return LegacyVpnProfileStore.list(prefix);
+    }
+}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index fe89903..ae0e001 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -16,6 +16,8 @@
 
 package com.android.server.content;
 
+import static android.os.PowerWhitelistManager.REASON_SYNC_MANAGER;
+
 import static com.android.server.content.SyncLogger.logSafe;
 
 import android.accounts.Account;
@@ -264,6 +266,10 @@
 
     private final SyncLogger mLogger;
 
+    // NOTE: this is a temporary allow-list for testing purposes; it will be removed before release.
+    private final String[] mEjSyncAllowedPackages = new String[]{
+            "com.google.android.google", "com.android.frameworks.servicestests"};
+
     private boolean isJobIdInUseLockedH(int jobId, List<JobInfo> pendingJobs) {
         for (JobInfo job: pendingJobs) {
             if (job.getId() == jobId) {
@@ -983,6 +989,14 @@
             }
         }
 
+        final boolean scheduleAsEj =
+                extras.getBoolean(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, false);
+        // NOTE: this is a temporary check for internal testing - to be removed before release.
+        if (scheduleAsEj && !ArrayUtils.contains(mEjSyncAllowedPackages, callingPackage)) {
+            throw new IllegalArgumentException(
+                    callingPackage + " is not allowed to schedule a sync as an EJ yet.");
+        }
+
         for (AccountAndUser account : accounts) {
             // If userId is specified, do not sync accounts of other users
             if (userId >= UserHandle.USER_SYSTEM && account.userId >= UserHandle.USER_SYSTEM
@@ -1490,6 +1504,12 @@
                         + logSafe(syncOperation.target));
                 backoff = new Pair<Long, Long>(SyncStorageEngine.NOT_IN_BACKOFF_MODE,
                         SyncStorageEngine.NOT_IN_BACKOFF_MODE);
+            } else {
+                // if an EJ is being backed-off but doesn't have SYNC_EXTRAS_IGNORE_BACKOFF set,
+                // reschedule it as a regular job
+                if (syncOperation.isScheduledAsExpeditedJob()) {
+                    syncOperation.scheduleEjAsRegularJob = true;
+                }
             }
             long now = SystemClock.elapsedRealtime();
             long backoffDelay = backoff.first == SyncStorageEngine.NOT_IN_BACKOFF_MODE ? 0
@@ -1640,6 +1660,10 @@
             b.setRequiresCharging(true);
         }
 
+        if (syncOperation.isScheduledAsExpeditedJob() && !syncOperation.scheduleEjAsRegularJob) {
+            b.setExpedited(true);
+        }
+
         if (syncOperation.syncExemptionFlag
                 == ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP) {
             DeviceIdleInternal dic =
@@ -1649,7 +1673,7 @@
                         syncOperation.owningPackage,
                         mConstants.getKeyExemptionTempWhitelistDurationInSeconds() * 1000,
                         UserHandle.getUserId(syncOperation.owningUid),
-                        /* sync=*/ false, "sync by top app");
+                        /* sync=*/ false, REASON_SYNC_MANAGER, "sync by top app");
             }
         }
 
@@ -3951,6 +3975,9 @@
         if (key.equals(ContentResolver.SYNC_EXTRAS_EXPEDITED)) {
             return true;
         }
+        if (key.equals(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB)) {
+            return true;
+        }
         if (key.equals(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS)) {
             return true;
         }
diff --git a/services/core/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java
index 4787635..c8654d1 100644
--- a/services/core/java/com/android/server/content/SyncOperation.java
+++ b/services/core/java/com/android/server/content/SyncOperation.java
@@ -103,6 +103,13 @@
     /** Stores the number of times this sync operation failed and had to be retried. */
     int retries;
 
+    /**
+     * Indicates if a sync that was originally scheduled as an EJ is being re-scheduled as a
+     * regular job. Specifically, this will be {@code true} if a sync is being backed-off but
+     * {@link ContentResolver#SYNC_EXTRAS_IGNORE_BACKOFF} is not set.
+     */
+    boolean scheduleEjAsRegularJob;
+
     /** jobId of the JobScheduler job corresponding to this sync */
     public int jobId;
 
@@ -408,6 +415,12 @@
         if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)) {
             sb.append(" EXPEDITED");
         }
+        if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, false)) {
+            sb.append(" EXPEDITED-JOB");
+            if (scheduleEjAsRegularJob) {
+                sb.append("(scheduled-as-regular)");
+            }
+        }
         switch (syncExemptionFlag) {
             case ContentResolver.SYNC_EXEMPTION_NONE:
                 break;
@@ -537,6 +550,11 @@
         return mImmutableExtras.getBoolean(ContentResolver.SYNC_EXTRAS_REQUIRE_CHARGING, false);
     }
 
+    boolean isScheduledAsExpeditedJob() {
+        return mImmutableExtras.getBoolean(
+                ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, false);
+    }
+
     boolean isAppStandbyExempted() {
         return syncExemptionFlag != ContentResolver.SYNC_EXEMPTION_NONE;
     }
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
index b3a6f26..658d27f 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
@@ -25,6 +25,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.hardware.devicestate.DeviceStateInfo;
 import android.hardware.devicestate.DeviceStateManager;
 import android.hardware.devicestate.IDeviceStateManager;
 import android.hardware.devicestate.IDeviceStateManagerCallback;
@@ -47,6 +48,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Optional;
 
 /**
@@ -76,6 +78,9 @@
 public final class DeviceStateManagerService extends SystemService {
     private static final String TAG = "DeviceStateManagerService";
     private static final boolean DEBUG = false;
+    // The device state to use as a placeholder before callback from the DeviceStateProvider occurs.
+    private static final DeviceState UNSPECIFIED_DEVICE_STATE =
+            new DeviceState(MINIMUM_DEVICE_STATE, "UNSPECIFIED");
 
     private final Object mLock = new Object();
     @NonNull
@@ -87,11 +92,11 @@
     @GuardedBy("mLock")
     private SparseArray<DeviceState> mDeviceStates = new SparseArray<>();
 
-    // The current committed device state. The default of UNSET will be replaced by
-    // the current state after the initial callback from the DeviceStateProvider.
+    // The current committed device state. The default of UNSPECIFIED_DEVICE_STATE will be replaced
+    // by the current state after the initial callback from the DeviceStateProvider.
     @GuardedBy("mLock")
     @NonNull
-    private DeviceState mCommittedState = new DeviceState(MINIMUM_DEVICE_STATE, "UNSET");
+    private DeviceState mCommittedState = UNSPECIFIED_DEVICE_STATE;
     // The device state that is currently awaiting callback from the policy to be committed.
     @GuardedBy("mLock")
     @NonNull
@@ -103,7 +108,7 @@
     // The device state that is set by the device state provider.
     @GuardedBy("mLock")
     @NonNull
-    private Optional<DeviceState> mBaseState = Optional.empty();
+    private DeviceState mBaseState = UNSPECIFIED_DEVICE_STATE;
 
     // List of processes registered to receive notifications about changes to device state and
     // request status indexed by process id.
@@ -166,7 +171,7 @@
      * @see #getOverrideState()
      */
     @NonNull
-    Optional<DeviceState> getBaseState() {
+    DeviceState getBaseState() {
         synchronized (mLock) {
             return mBaseState;
         }
@@ -203,33 +208,47 @@
     /** Returns the list of currently supported device state identifiers. */
     private int[] getSupportedStateIdentifiers() {
         synchronized (mLock) {
-            int[] supportedStates = new int[mDeviceStates.size()];
-            for (int i = 0; i < supportedStates.length; i++) {
-                supportedStates[i] = mDeviceStates.valueAt(i).getIdentifier();
-            }
-            return supportedStates;
+            return getSupportedStateIdentifiersLocked();
         }
     }
 
+    /** Returns the list of currently supported device state identifiers. */
+    private int[] getSupportedStateIdentifiersLocked() {
+        int[] supportedStates = new int[mDeviceStates.size()];
+        for (int i = 0; i < supportedStates.length; i++) {
+            supportedStates[i] = mDeviceStates.valueAt(i).getIdentifier();
+        }
+        return supportedStates;
+    }
+
+    @NonNull
+    private DeviceStateInfo getDeviceStateInfoLocked() {
+        final int[] supportedStates = getSupportedStateIdentifiersLocked();
+        final int baseState = mBaseState.getIdentifier();
+        final int currentState = mCommittedState.getIdentifier();
+
+        return new DeviceStateInfo(supportedStates, baseState, currentState);
+    }
+
     @VisibleForTesting
     IDeviceStateManager getBinderService() {
         return mBinderService;
     }
 
     private void updateSupportedStates(DeviceState[] supportedDeviceStates) {
+        boolean updatedPendingState;
         synchronized (mLock) {
+            final int[] oldStateIdentifiers = getSupportedStateIdentifiersLocked();
+
             mDeviceStates.clear();
             for (int i = 0; i < supportedDeviceStates.length; i++) {
                 DeviceState state = supportedDeviceStates[i];
                 mDeviceStates.put(state.getIdentifier(), state);
             }
 
-            if (mBaseState.isPresent()
-                    && !isSupportedStateLocked(mBaseState.get().getIdentifier())) {
-                // The current base state is no longer valid. We'll clear it here, though
-                // we won't actually update the current state until a callback comes from the
-                // provider with the most recent state.
-                mBaseState = Optional.empty();
+            final int[] newStateIdentifiers = getSupportedStateIdentifiersLocked();
+            if (Arrays.equals(oldStateIdentifiers, newStateIdentifiers)) {
+                return;
             }
 
             final int requestSize = mRequestRecords.size();
@@ -240,7 +259,14 @@
                 }
             }
 
-            updatePendingStateLocked();
+            updatedPendingState = updatePendingStateLocked();
+        }
+
+        if (!updatedPendingState) {
+            // If the change in the supported states didn't result in a change of the pending state
+            // commitPendingState() will never be called and the callbacks will never be notified
+            // of the change.
+            notifyDeviceStateInfoChanged();
         }
 
         notifyRequestsOfStatusChangeIfNeeded();
@@ -265,23 +291,25 @@
     }
 
     /**
-     * Requests to set the base state. The request may not be honored under certain conditions, for
-     * example if the provided state is not supported.
+     * Sets the base state.
+     *
+     * @throws IllegalArgumentException if the {@code identifier} is not a supported state.
      *
      * @see #isSupportedStateLocked(int)
      */
     private void setBaseState(int identifier) {
+        boolean updatedPendingState;
         synchronized (mLock) {
-            if (mBaseState.isPresent() && mBaseState.get().getIdentifier() == identifier) {
-                // Base state hasn't changed. Nothing to do.
-                return;
-            }
-
-            final Optional<DeviceState> baseState = getStateLocked(identifier);
-            if (!baseState.isPresent()) {
+            final Optional<DeviceState> baseStateOptional = getStateLocked(identifier);
+            if (!baseStateOptional.isPresent()) {
                 throw new IllegalArgumentException("Base state is not supported");
             }
 
+            final DeviceState baseState = baseStateOptional.get();
+            if (mBaseState.equals(baseState)) {
+                // Base state hasn't changed. Nothing to do.
+                return;
+            }
             mBaseState = baseState;
 
             final int requestSize = mRequestRecords.size();
@@ -292,7 +320,14 @@
                 }
             }
 
-            updatePendingStateLocked();
+            updatedPendingState = updatePendingStateLocked();
+        }
+
+        if (!updatedPendingState) {
+            // If the change in base state didn't result in a change of the pending state
+            // commitPendingState() will never be called and the callbacks will never be notified
+            // of the change.
+            notifyDeviceStateInfoChanged();
         }
 
         notifyRequestsOfStatusChangeIfNeeded();
@@ -303,32 +338,39 @@
      * Tries to update the current pending state with the current requested state. Must call
      * {@link #notifyPolicyIfNeeded()} to actually notify the policy that the state is being
      * changed.
+     *
+     * @return {@code true} if the pending state has changed as a result of this call, {@code false}
+     * otherwise.
      */
-    private void updatePendingStateLocked() {
+    private boolean updatePendingStateLocked() {
         if (mPendingState.isPresent()) {
             // Have pending state, can not configure a new state until the state is committed.
-            return;
+            return false;
         }
 
         final DeviceState stateToConfigure;
         if (!mRequestRecords.isEmpty()) {
             stateToConfigure = mRequestRecords.get(mRequestRecords.size() - 1).mRequestedState;
+        } else if (isSupportedStateLocked(mBaseState.getIdentifier())) {
+            // Base state could have recently become unsupported after a change in supported states.
+            stateToConfigure = mBaseState;
         } else {
-            stateToConfigure = mBaseState.orElse(null);
+            stateToConfigure = null;
         }
 
         if (stateToConfigure == null) {
             // No currently requested state.
-            return;
+            return false;
         }
 
-        if (stateToConfigure == mCommittedState) {
+        if (stateToConfigure.equals(mCommittedState)) {
             // The state requesting to be committed already matches the current committed state.
-            return;
+            return false;
         }
 
         mPendingState = Optional.of(stateToConfigure);
         mIsPolicyWaitingForState = true;
+        return true;
     }
 
     /**
@@ -374,18 +416,22 @@
      */
     private void commitPendingState() {
         // Update the current state.
-        int newState;
         synchronized (mLock) {
             if (DEBUG) {
                 Slog.d(TAG, "Committing state: " + mPendingState);
             }
             mCommittedState = mPendingState.get();
-            newState = mCommittedState.getIdentifier();
 
             if (!mRequestRecords.isEmpty()) {
                 final OverrideRequestRecord topRequest =
                         mRequestRecords.get(mRequestRecords.size() - 1);
-                topRequest.setStatusLocked(OverrideRequestRecord.STATUS_ACTIVE);
+                if (topRequest.mRequestedState.getIdentifier() == mCommittedState.getIdentifier()) {
+                    // The top request could have come in while the service was awaiting callback
+                    // from the policy. In that case we only set it to active if it matches the
+                    // current committed state, otherwise it will be set to active when its
+                    // requested state is committed.
+                    topRequest.setStatusLocked(OverrideRequestRecord.STATUS_ACTIVE);
+                }
             }
 
             mPendingState = Optional.empty();
@@ -393,7 +439,7 @@
         }
 
         // Notify callbacks of a change.
-        notifyDeviceStateChanged(newState);
+        notifyDeviceStateInfoChanged();
 
         // Notify the top request that it's active.
         notifyRequestsOfStatusChangeIfNeeded();
@@ -402,14 +448,15 @@
         notifyPolicyIfNeeded();
     }
 
-    private void notifyDeviceStateChanged(int deviceState) {
+    private void notifyDeviceStateInfoChanged() {
         if (Thread.holdsLock(mLock)) {
             throw new IllegalStateException(
                     "Attempting to notify callbacks with service lock held.");
         }
 
-        // Grab the lock and copy the process records.
+        // Grab the lock and copy the process records and the current info.
         ArrayList<ProcessRecord> registeredProcesses;
+        DeviceStateInfo info;
         synchronized (mLock) {
             if (mProcessRecords.size() == 0) {
                 return;
@@ -419,11 +466,13 @@
             for (int i = 0; i < mProcessRecords.size(); i++) {
                 registeredProcesses.add(mProcessRecords.valueAt(i));
             }
+
+            info = getDeviceStateInfoLocked();
         }
 
         // After releasing the lock, send the notifications out.
         for (int i = 0; i < registeredProcesses.size(); i++) {
-            registeredProcesses.get(i).notifyDeviceStateAsync(deviceState);
+            registeredProcesses.get(i).notifyDeviceStateInfoAsync(info);
         }
     }
 
@@ -454,28 +503,20 @@
     }
 
     private void registerProcess(int pid, IDeviceStateManagerCallback callback) {
-        int currentState;
-        ProcessRecord record;
-        // Grab the lock to register the callback and get the current state.
         synchronized (mLock) {
             if (mProcessRecords.contains(pid)) {
                 throw new SecurityException("The calling process has already registered an"
                         + " IDeviceStateManagerCallback.");
             }
 
-            record = new ProcessRecord(callback, pid);
+            ProcessRecord record = new ProcessRecord(callback, pid);
             try {
                 callback.asBinder().linkToDeath(record, 0);
             } catch (RemoteException ex) {
                 throw new RuntimeException(ex);
             }
-
             mProcessRecords.put(pid, record);
-            currentState = mCommittedState.getIdentifier();
         }
-
-        // Notify the callback of the state at registration.
-        record.notifyDeviceStateAsync(currentState);
     }
 
     private void handleProcessDied(ProcessRecord processRecord) {
@@ -528,10 +569,13 @@
                     new OverrideRequestRecord(processRecord, token, deviceState.get(), flags);
             mRequestRecords.add(request);
             processRecord.mRequestRecords.put(request.mToken, request);
-            // We don't set the status of the new request to ACTIVE here as it will be set in
-            // commitPendingState().
 
-            updatePendingStateLocked();
+            final boolean updatedPendingState = updatePendingStateLocked();
+            if (!updatedPendingState && !mPendingState.isPresent()) {
+                // We don't set the status of the new request to ACTIVE if the request updated the
+                // pending state as it will be set in commitPendingState().
+                request.setStatusLocked(OverrideRequestRecord.STATUS_ACTIVE, true /* markDirty */);
+            }
         }
 
         notifyRequestsOfStatusChangeIfNeeded();
@@ -626,9 +670,9 @@
             handleProcessDied(this);
         }
 
-        public void notifyDeviceStateAsync(int devicestate) {
+        public void notifyDeviceStateInfoAsync(@NonNull DeviceStateInfo info) {
             try {
-                mCallback.onDeviceStateChanged(devicestate);
+                mCallback.onDeviceStateInfoChanged(info);
             } catch (RemoteException ex) {
                 Slog.w(TAG, "Failed to notify process " + mPid + " that device state changed.",
                         ex);
@@ -752,6 +796,13 @@
     /** Implementation of {@link IDeviceStateManager} published as a binder service. */
     private final class BinderService extends IDeviceStateManager.Stub {
         @Override // Binder call
+        public DeviceStateInfo getDeviceStateInfo() {
+            synchronized (mLock) {
+                return getDeviceStateInfoLocked();
+            }
+        }
+
+        @Override // Binder call
         public void registerCallback(IDeviceStateManagerCallback callback) {
             if (callback == null) {
                 throw new IllegalArgumentException("Device state callback must not be null.");
@@ -767,16 +818,6 @@
         }
 
         @Override // Binder call
-        public int[] getSupportedDeviceStates() {
-            final long token = Binder.clearCallingIdentity();
-            try {
-                return getSupportedStateIdentifiers();
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override // Binder call
         public void requestState(IBinder token, int state, int flags) {
             getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE,
                     "Permission required to request device state.");
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java
index 6cc55a6..f346600 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java
@@ -64,13 +64,13 @@
 
     private void printState(PrintWriter pw) {
         DeviceState committedState = mService.getCommittedState();
-        Optional<DeviceState> baseState = mService.getBaseState();
+        DeviceState baseState = mService.getBaseState();
         Optional<DeviceState> overrideState = mService.getOverrideState();
 
         pw.println("Committed state: " + committedState);
         if (overrideState.isPresent()) {
             pw.println("----------------------");
-            pw.println("Base state: " + baseState.orElse(null));
+            pw.println("Base state: " + baseState);
             pw.println("Override state: " + overrideState.get());
         }
     }
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index a62f67a..30cbf27 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -61,7 +61,10 @@
     private static final Plog PLOG = Plog.createSystemPlog(TAG);
 
     @Nullable
-    public static BrightnessMappingStrategy create(Resources resources) {
+    public static BrightnessMappingStrategy create(Resources resources,
+            DisplayDeviceConfig displayDeviceConfig) {
+
+        // Display independent values
         float[] luxLevels = getLuxLevels(resources.getIntArray(
                 com.android.internal.R.array.config_autoBrightnessLevels));
         int[] brightnessLevelsBacklight = resources.getIntArray(
@@ -71,32 +74,22 @@
         float autoBrightnessAdjustmentMaxGamma = resources.getFraction(
                 com.android.internal.R.fraction.config_autoBrightnessAdjustmentMaxGamma,
                 1, 1);
-
-        float[] nitsRange = getFloatArray(resources.obtainTypedArray(
-                com.android.internal.R.array.config_screenBrightnessNits));
-        int[] backlightRange = resources.getIntArray(
-                com.android.internal.R.array.config_screenBrightnessBacklight);
-
         long shortTermModelTimeout = resources.getInteger(
                 com.android.internal.R.integer.config_autoBrightnessShortTermModelTimeout);
 
-        if (isValidMapping(nitsRange, backlightRange)
+        // Display dependent values - used for physical mapping strategy nits -> brightness
+        final float[] nitsRange = displayDeviceConfig.getNits();
+        final float[] brightnessRange = displayDeviceConfig.getBrightness();
+
+        if (isValidMapping(nitsRange, brightnessRange)
                 && isValidMapping(luxLevels, brightnessLevelsNits)) {
-            int minimumBacklight = resources.getInteger(
-                    com.android.internal.R.integer.config_screenBrightnessSettingMinimum);
-            int maximumBacklight = resources.getInteger(
-                    com.android.internal.R.integer.config_screenBrightnessSettingMaximum);
-            if (backlightRange[0] > minimumBacklight
-                    || backlightRange[backlightRange.length - 1] < maximumBacklight) {
-                Slog.w(TAG, "Screen brightness mapping does not cover whole range of available " +
-                        "backlight values, autobrightness functionality may be impaired.");
-            }
+
             BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(
                     luxLevels, brightnessLevelsNits);
             builder.setShortTermModelTimeoutMillis(shortTermModelTimeout);
             builder.setShortTermModelLowerLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO);
             builder.setShortTermModelUpperLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO);
-            return new PhysicalMappingStrategy(builder.build(), nitsRange, backlightRange,
+            return new PhysicalMappingStrategy(builder.build(), nitsRange, brightnessRange,
                     autoBrightnessAdjustmentMaxGamma);
         } else if (isValidMapping(luxLevels, brightnessLevelsBacklight)) {
             return new SimpleMappingStrategy(luxLevels, brightnessLevelsBacklight,
@@ -264,11 +257,11 @@
     public abstract boolean setAutoBrightnessAdjustment(float adjustment);
 
     /**
-     * Converts the provided backlight value to nits if possible.
+     * Converts the provided brightness value to nits if possible.
      *
-     * Returns -1.0f if there's no available mapping for the backlight to nits.
+     * Returns -1.0f if there's no available mapping for the brightness to nits.
      */
-    public abstract float convertToNits(int backlight);
+    public abstract float convertToNits(float brightness);
 
     /**
      * Adds a user interaction data point to the brightness mapping.
@@ -603,7 +596,7 @@
         }
 
         @Override
-        public float convertToNits(int backlight) {
+        public float convertToNits(float brightness) {
             return -1.0f;
         }
 
@@ -701,37 +694,39 @@
         // in nits.
         private Spline mBrightnessSpline;
 
-        // A spline mapping from nits to the corresponding backlight value, normalized to the range
+        // A spline mapping from nits to the corresponding brightness value, normalized to the range
         // [0, 1.0].
-        private Spline mNitsToBacklightSpline;
+        private Spline mNitsToBrightnessSpline;
+
+        // A spline mapping from the system brightness value, normalized to the range [0, 1.0], to
+        // a brightness in nits.
+        private Spline mBrightnessToNitsSpline;
 
         // The default brightness configuration.
         private final BrightnessConfiguration mDefaultConfig;
 
-        // A spline mapping from the device's backlight value, normalized to the range [0, 1.0], to
-        // a brightness in nits.
-        private Spline mBacklightToNitsSpline;
-
-        private float[] mNits;
-        private int[] mBacklight;
+        private final float[] mNits;
+        private final float[] mBrightness;
 
         private boolean mBrightnessRangeAdjustmentApplied;
 
-        private float mMaxGamma;
+        private final float mMaxGamma;
         private float mAutoBrightnessAdjustment;
         private float mUserLux;
         private float mUserBrightness;
 
         public PhysicalMappingStrategy(BrightnessConfiguration config, float[] nits,
-                                       int[] backlight, float maxGamma) {
-            Preconditions.checkArgument(nits.length != 0 && backlight.length != 0,
-                    "Nits and backlight arrays must not be empty!");
-            Preconditions.checkArgument(nits.length == backlight.length,
-                    "Nits and backlight arrays must be the same length!");
+                float[] brightness, float maxGamma) {
+
+            Preconditions.checkArgument(nits.length != 0 && brightness.length != 0,
+                    "Nits and brightness arrays must not be empty!");
+
+            Preconditions.checkArgument(nits.length == brightness.length,
+                    "Nits and brightness arrays must be the same length!");
             Objects.requireNonNull(config);
             Preconditions.checkArrayElementsInRange(nits, 0, Float.MAX_VALUE, "nits");
-            Preconditions.checkArrayElementsInRange(backlight,
-                    PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON, "backlight");
+            Preconditions.checkArrayElementsInRange(brightness,
+                    PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, "brightness");
 
             mMaxGamma = maxGamma;
             mAutoBrightnessAdjustment = 0;
@@ -739,7 +734,7 @@
             mUserBrightness = -1;
 
             mNits = nits;
-            mBacklight = backlight;
+            mBrightness = brightness;
             computeNitsBrightnessSplines(mNits);
 
             mDefaultConfig = config;
@@ -784,15 +779,15 @@
         public float getBrightness(float lux, String packageName,
                 @ApplicationInfo.Category int category) {
             float nits = mBrightnessSpline.interpolate(lux);
-            float backlight = mNitsToBacklightSpline.interpolate(nits);
+            float brightness = mNitsToBrightnessSpline.interpolate(nits);
             // Correct the brightness according to the current application and its category, but
-            // only if no user data point is set (as this will oevrride the user setting).
+            // only if no user data point is set (as this will override the user setting).
             if (mUserLux == -1) {
-                backlight = correctBrightness(backlight, packageName, category);
+                brightness = correctBrightness(brightness, packageName, category);
             } else if (mLoggingEnabled) {
                 Slog.d(TAG, "user point set, correction not applied");
             }
-            return backlight;
+            return brightness;
         }
 
         @Override
@@ -817,8 +812,8 @@
         }
 
         @Override
-        public float convertToNits(int backlight) {
-            return mBacklightToNitsSpline.interpolate(normalizeAbsoluteBrightness(backlight));
+        public float convertToNits(float brightness) {
+            return mBrightnessToNitsSpline.interpolate(brightness);
         }
 
         @Override
@@ -884,7 +879,8 @@
             pw.println("PhysicalMappingStrategy");
             pw.println("  mConfig=" + mConfig);
             pw.println("  mBrightnessSpline=" + mBrightnessSpline);
-            pw.println("  mNitsToBacklightSpline=" + mNitsToBacklightSpline);
+            pw.println("  mNitsToBrightnessSpline=" + mNitsToBrightnessSpline);
+            pw.println("  mBrightnessToNitsSpline=" + mBrightnessToNitsSpline);
             pw.println("  mMaxGamma=" + mMaxGamma);
             pw.println("  mAutoBrightnessAdjustment=" + mAutoBrightnessAdjustment);
             pw.println("  mUserLux=" + mUserLux);
@@ -894,31 +890,25 @@
         }
 
         private void computeNitsBrightnessSplines(float[] nits) {
-            final int len = nits.length;
-            float[] normalizedBacklight = new float[len];
-            for (int i = 0; i < len; i++) {
-                normalizedBacklight[i] = normalizeAbsoluteBrightness(mBacklight[i]);
-            }
-
-            mNitsToBacklightSpline = Spline.createSpline(nits, normalizedBacklight);
-            mBacklightToNitsSpline = Spline.createSpline(normalizedBacklight, nits);
+            mNitsToBrightnessSpline = Spline.createSpline(nits, mBrightness);
+            mBrightnessToNitsSpline = Spline.createSpline(mBrightness, nits);
         }
 
         private void computeSpline() {
             Pair<float[], float[]> defaultCurve = mConfig.getCurve();
             float[] defaultLux = defaultCurve.first;
             float[] defaultNits = defaultCurve.second;
-            float[] defaultBacklight = new float[defaultNits.length];
-            for (int i = 0; i < defaultBacklight.length; i++) {
-                defaultBacklight[i] = mNitsToBacklightSpline.interpolate(defaultNits[i]);
+            float[] defaultBrightness = new float[defaultNits.length];
+            for (int i = 0; i < defaultBrightness.length; i++) {
+                defaultBrightness[i] = mNitsToBrightnessSpline.interpolate(defaultNits[i]);
             }
-            Pair<float[], float[]> curve = getAdjustedCurve(defaultLux, defaultBacklight, mUserLux,
+            Pair<float[], float[]> curve = getAdjustedCurve(defaultLux, defaultBrightness, mUserLux,
                     mUserBrightness, mAutoBrightnessAdjustment, mMaxGamma);
             float[] lux = curve.first;
-            float[] backlight = curve.second;
-            float[] nits = new float[backlight.length];
+            float[] brightness = curve.second;
+            float[] nits = new float[brightness.length];
             for (int i = 0; i < nits.length; i++) {
-                nits[i] = mBacklightToNitsSpline.interpolate(backlight[i]);
+                nits[i] = mBrightnessToNitsSpline.interpolate(brightness[i]);
             }
             mBrightnessSpline = Spline.createSpline(lux, nits);
         }
@@ -926,7 +916,7 @@
         private float getUnadjustedBrightness(float lux) {
             Pair<float[], float[]> curve = mConfig.getCurve();
             Spline spline = Spline.createSpline(curve.first, curve.second);
-            return mNitsToBacklightSpline.interpolate(spline.interpolate(lux));
+            return mNitsToBrightnessSpline.interpolate(spline.interpolate(lux));
         }
 
         private float correctBrightness(float brightness, String packageName, int category) {
diff --git a/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java b/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java
index d4556ed..1acd5d0 100644
--- a/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java
+++ b/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java
@@ -16,17 +16,26 @@
 
 package com.android.server.display;
 
-import android.content.Context;
 import android.hardware.devicestate.DeviceStateManager;
-import android.text.TextUtils;
+import android.os.Environment;
 import android.util.IndentingPrintWriter;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.DisplayAddress;
 
+import com.android.server.display.config.layout.Layouts;
+import com.android.server.display.config.layout.XmlParser;
 import com.android.server.display.layout.Layout;
 
-import java.util.Arrays;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.xml.datatype.DatatypeConfigurationException;
 
 /**
  * Mapping from device states into {@link Layout}s. This allows us to map device
@@ -39,15 +48,14 @@
 
     public static final int STATE_DEFAULT = DeviceStateManager.INVALID_DEVICE_STATE;
 
-    // TODO - b/168208162 - Remove these when we check in static definitions for layouts
-    public static final int STATE_FOLDED = 100;
-    public static final int STATE_UNFOLDED = 101;
+    private static final String CONFIG_FILE_PATH =
+            "etc/displayconfig/display_layout_configuration.xml";
 
     private final SparseArray<Layout> mLayoutMap = new SparseArray<>();
 
-    DeviceStateToLayoutMap(Context context) {
-        mLayoutMap.append(STATE_DEFAULT, new Layout());
-        loadFoldedDisplayConfig(context);
+    DeviceStateToLayoutMap() {
+        loadLayoutsFromConfig();
+        createLayout(STATE_DEFAULT);
     }
 
     public void dumpLocked(IndentingPrintWriter ipw) {
@@ -68,7 +76,7 @@
         return layout;
     }
 
-    private Layout create(int state) {
+    private Layout createLayout(int state) {
         if (mLayoutMap.contains(state)) {
             Slog.e(TAG, "Attempted to create a second layout for state " + state);
             return null;
@@ -79,43 +87,37 @@
         return layout;
     }
 
-    private void loadFoldedDisplayConfig(Context context) {
-        final String[] strDisplayIds = context.getResources().getStringArray(
-                com.android.internal.R.array.config_internalFoldedPhysicalDisplayIds);
+    /**
+     * Reads display-layout-configuration files to get the layouts to use for this device.
+     */
+    private void loadLayoutsFromConfig() {
+        final File configFile = Environment.buildPath(
+                Environment.getVendorDirectory(), CONFIG_FILE_PATH);
 
-        if (strDisplayIds.length != 2 || TextUtils.isEmpty(strDisplayIds[0])
-                || TextUtils.isEmpty(strDisplayIds[1])) {
-            Slog.w(TAG, "Folded display configuration invalid: [" + Arrays.toString(strDisplayIds)
-                    + "]");
+        if (!configFile.exists()) {
             return;
         }
 
-        final long[] displayIds;
-        try {
-            displayIds = new long[] {
-                Long.parseLong(strDisplayIds[0]),
-                Long.parseLong(strDisplayIds[1])
-            };
-        } catch (NumberFormatException nfe) {
-            Slog.w(TAG, "Folded display config non numerical: " + Arrays.toString(strDisplayIds));
-            return;
+        Slog.i(TAG, "Loading display layouts from " + configFile);
+        try (InputStream in = new BufferedInputStream(new FileInputStream(configFile))) {
+            final Layouts layouts = XmlParser.read(in);
+            if (layouts == null) {
+                Slog.i(TAG, "Display layout config not found: " + configFile);
+                return;
+            }
+            for (com.android.server.display.config.layout.Layout l : layouts.getLayout()) {
+                final int state = l.getState().intValue();
+                final Layout layout = createLayout(state);
+                for (com.android.server.display.config.layout.Display d: l.getDisplay()) {
+                    layout.createDisplayLocked(
+                            DisplayAddress.fromPhysicalDisplayId(d.getAddress().longValue()),
+                            d.getIsDefault(),
+                            d.getEnabled());
+                }
+            }
+        } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
+            Slog.e(TAG, "Encountered an error while reading/parsing display layout config file: "
+                    + configFile, e);
         }
-
-        final int[] foldedDeviceStates = context.getResources().getIntArray(
-                com.android.internal.R.array.config_foldedDeviceStates);
-        // Only add folded states if folded state config is not empty
-        if (foldedDeviceStates.length == 0) {
-            return;
-        }
-
-        // Create the folded state layout
-        final Layout foldedLayout = create(STATE_FOLDED);
-        foldedLayout.createDisplayLocked(
-                DisplayAddress.fromPhysicalDisplayId(displayIds[0]), true /*isDefault*/);
-
-        // Create the unfolded state layout
-        final Layout unfoldedLayout = create(STATE_UNFOLDED);
-        unfoldedLayout.createDisplayLocked(
-                DisplayAddress.fromPhysicalDisplayId(displayIds[1]), true /*isDefault*/);
     }
 }
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 49328f1..0071b2f 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -18,9 +18,12 @@
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.content.res.Resources;
 import android.os.Environment;
 import android.os.PowerManager;
+import android.util.MathUtils;
 import android.util.Slog;
+import android.util.Spline;
 import android.view.DisplayAddress;
 
 import com.android.internal.R;
@@ -72,15 +75,31 @@
 
     private final Context mContext;
 
+    // Nits and backlight values that are loaded from either the display device config file, or
+    // config.xml. These are the raw values and just used for the dumpsys
+    private float[] mRawNits;
+    private float[] mRawBacklight;
+
+    // These arrays are calculated from the raw arrays, but clamped to contain values equal to and
+    // between mBacklightMinimum and mBacklightMaximum. These three arrays should all be the same
+    // length
+    // Nits array that is used to store the entire range of nits values that the device supports
     private float[] mNits;
+    // Backlight array holds the values that the HAL uses to display the corresponding nits values
+    private float[] mBacklight;
+    // Purely an array that covers the ranges of values 0.0 - 1.0, indicating the system brightness
+    // for the corresponding values above
     private float[] mBrightness;
-    private float mBrightnessMinimum = Float.NaN;
-    private float mBrightnessMaximum = Float.NaN;
+
+    private float mBacklightMinimum = Float.NaN;
+    private float mBacklightMaximum = Float.NaN;
     private float mBrightnessDefault = Float.NaN;
     private float mBrightnessRampFastDecrease = Float.NaN;
     private float mBrightnessRampFastIncrease = Float.NaN;
     private float mBrightnessRampSlowDecrease = Float.NaN;
     private float mBrightnessRampSlowIncrease = Float.NaN;
+    private Spline mBrightnessToBacklightSpline;
+    private Spline mBacklightToBrightnessSpline;
     private List<String> mQuirks;
     private boolean mIsHighBrightnessModeEnabled = false;
     private HighBrightnessModeData mHbmData;
@@ -167,7 +186,7 @@
     }
 
     /**
-     * Return the brightness mapping nits array if one is defined in the configuration file.
+     * Return the brightness mapping nits array.
      *
      * @return The brightness mapping nits array.
      */
@@ -176,22 +195,40 @@
     }
 
     /**
-     * Return the brightness mapping value array if one is defined in the configuration file.
+     * Return the brightness mapping backlight array.
      *
-     * @return The brightness mapping value array.
+     * @return The backlight mapping value array.
+     */
+    public float[] getBacklight() {
+        return mBacklight;
+    }
+
+    /**
+     * Calculates the backlight value, as recognised by the HAL, from the brightness value
+     * given that the rest of the system deals with.
+     *
+     * @param brightness value on the framework scale of 0-1
+     * @return backlight value on the HAL scale of 0-1
+     */
+    public float getBacklightFromBrightness(float brightness) {
+        return mBrightnessToBacklightSpline.interpolate(brightness);
+    }
+
+    /**
+     * Return an array of equal length to backlight and nits, that covers the entire system
+     * brightness range of 0.0-1.0.
+     *
+     * @return brightness array
      */
     public float[] getBrightness() {
         return mBrightness;
     }
 
-    public float getBrightnessMinimum() {
-        return mBrightnessMinimum;
-    }
-
-    public float getBrightnessMaximum() {
-        return mBrightnessMaximum;
-    }
-
+    /**
+     * Return the default brightness on a scale of 0.0f - 1.0f
+     *
+     * @return default brightness
+     */
     public float getBrightnessDefault() {
         return mBrightnessDefault;
     }
@@ -237,10 +274,15 @@
     @Override
     public String toString() {
         String str = "DisplayDeviceConfig{"
-                + "mBrightness=" + Arrays.toString(mBrightness)
+                + "mBacklight=" + Arrays.toString(mBacklight)
                 + ", mNits=" + Arrays.toString(mNits)
-                + ", mBrightnessMinimum=" + mBrightnessMinimum
-                + ", mBrightnessMaximum=" + mBrightnessMaximum
+                + ", mRawBacklight=" + Arrays.toString(mRawBacklight)
+                + ", mRawNits=" + Arrays.toString(mRawNits)
+                + ", mBrightness=" + Arrays.toString(mBrightness)
+                + ", mBrightnessToBacklightSpline=" + mBrightnessToBacklightSpline
+                + ", mBacklightToBrightnessSpline=" + mBacklightToBrightnessSpline
+                + ", mBacklightMinimum=" + mBacklightMinimum
+                + ", mBacklightMaximum=" + mBacklightMaximum
                 + ", mBrightnessDefault=" + mBrightnessDefault
                 + ", mQuirks=" + mQuirks
                 + ", isHbmEnabled=" + mIsHighBrightnessModeEnabled
@@ -253,10 +295,6 @@
         return str;
     }
 
-    private float getMaxBrightness() {
-        return mBrightness[mBrightness.length - 1];
-    }
-
     private static DisplayDeviceConfig getConfigFromSuffix(Context context, File baseDirectory,
             String suffixFormat, long idNumber) {
 
@@ -264,7 +302,6 @@
         final String filename = String.format(CONFIG_FILE_FORMAT, suffix);
         final File filePath = Environment.buildPath(
                 baseDirectory, ETC_DIR, DISPLAY_CONFIG_DIR, filename);
-
         if (filePath.exists()) {
             final DisplayDeviceConfig config = new DisplayDeviceConfig(context);
             config.initFromFile(filePath);
@@ -299,9 +336,9 @@
         try (InputStream in = new BufferedInputStream(new FileInputStream(configFile))) {
             final DisplayConfiguration config = XmlParser.read(in);
             if (config != null) {
-                loadBrightnessMap(config);
                 loadBrightnessDefaultFromDdcXml(config);
                 loadBrightnessConstraintsFromConfigXml();
+                loadBrightnessMap(config);
                 loadHighBrightnessModeData(config);
                 loadQuirks(config);
                 loadBrightnessRamps(config);
@@ -318,13 +355,20 @@
         // If no ddc exists, use config.xml
         loadBrightnessDefaultFromConfigXml();
         loadBrightnessConstraintsFromConfigXml();
+        loadBrightnessMapFromConfigXml();
         loadBrightnessRampsFromConfigXml();
     }
 
     private void initFromPmValues() {
-        mBrightnessMinimum = PowerManager.BRIGHTNESS_MIN;
-        mBrightnessMaximum = PowerManager.BRIGHTNESS_MAX;
+        // Set all to basic values
+        mBacklightMinimum = PowerManager.BRIGHTNESS_MIN;
+        mBacklightMaximum = PowerManager.BRIGHTNESS_MAX;
         mBrightnessDefault = BRIGHTNESS_DEFAULT;
+        mBrightnessRampFastDecrease = PowerManager.BRIGHTNESS_MAX;
+        mBrightnessRampFastIncrease = PowerManager.BRIGHTNESS_MAX;
+        mBrightnessRampSlowDecrease = PowerManager.BRIGHTNESS_MAX;
+        mBrightnessRampSlowIncrease = PowerManager.BRIGHTNESS_MAX;
+        setSimpleMappingStrategyValues();
     }
 
     private void loadBrightnessDefaultFromDdcXml(DisplayConfiguration config) {
@@ -364,24 +408,27 @@
         final float max = mContext.getResources().getFloat(com.android.internal.R.dimen
                 .config_screenBrightnessSettingMaximumFloat);
         if (min == INVALID_BRIGHTNESS_IN_CONFIG || max == INVALID_BRIGHTNESS_IN_CONFIG) {
-            mBrightnessMinimum = BrightnessSynchronizer.brightnessIntToFloat(
+            mBacklightMinimum = BrightnessSynchronizer.brightnessIntToFloat(
                     mContext.getResources().getInteger(com.android.internal.R.integer
                             .config_screenBrightnessSettingMinimum));
-            mBrightnessMaximum = BrightnessSynchronizer.brightnessIntToFloat(
+            mBacklightMaximum = BrightnessSynchronizer.brightnessIntToFloat(
                     mContext.getResources().getInteger(com.android.internal.R.integer
                             .config_screenBrightnessSettingMaximum));
         } else {
-            mBrightnessMinimum = min;
-            mBrightnessMaximum = max;
+            mBacklightMinimum = min;
+            mBacklightMaximum = max;
         }
     }
 
     private void loadBrightnessMap(DisplayConfiguration config) {
         final NitsMap map = config.getScreenBrightnessMap();
-        // Map may not exist in config file
+        // Map may not exist in display device config
         if (map == null) {
+            loadBrightnessMapFromConfigXml();
             return;
         }
+
+        // Use the (preferred) display device config mapping
         final List<Point> points = map.getPoint();
         final int size = points.size();
 
@@ -408,8 +455,123 @@
             }
             ++i;
         }
-        mNits = nits;
-        mBrightness = backlight;
+        mRawNits = nits;
+        mRawBacklight = backlight;
+        constrainNitsAndBacklightArrays();
+    }
+
+    private void loadBrightnessMapFromConfigXml() {
+        // Use the config.xml mapping
+        final Resources res = mContext.getResources();
+        final float[] sysNits = BrightnessMappingStrategy.getFloatArray(res.obtainTypedArray(
+                com.android.internal.R.array.config_screenBrightnessNits));
+        final int[] sysBrightness = res.getIntArray(
+                com.android.internal.R.array.config_screenBrightnessBacklight);
+        final float[] sysBrightnessFloat = new float[sysBrightness.length];
+
+        for (int i = 0; i < sysBrightness.length; i++) {
+            sysBrightnessFloat[i] = BrightnessSynchronizer.brightnessIntToFloat(
+                    sysBrightness[i]);
+        }
+
+        // These arrays are allowed to be empty, we set null values so that
+        // BrightnessMappingStrategy will create a SimpleMappingStrategy instead.
+        if (sysBrightnessFloat.length == 0 || sysNits.length == 0) {
+            setSimpleMappingStrategyValues();
+            return;
+        }
+
+        mRawNits = sysNits;
+        mRawBacklight = sysBrightnessFloat;
+        constrainNitsAndBacklightArrays();
+    }
+
+    private void setSimpleMappingStrategyValues() {
+        // No translation from backlight to brightness should occur if we are using a
+        // SimpleMappingStrategy (ie they should be the same) so the splines are
+        // set to be linear, between 0.0 and 1.0
+        mNits = null;
+        mBacklight = null;
+        float[] simpleMappingStrategyArray = new float[]{0.0f, 1.0f};
+        mBrightnessToBacklightSpline = Spline.createSpline(simpleMappingStrategyArray,
+                simpleMappingStrategyArray);
+        mBacklightToBrightnessSpline = Spline.createSpline(simpleMappingStrategyArray,
+                simpleMappingStrategyArray);
+    }
+
+    /**
+     * Change the nits and backlight arrays, so that they cover only the allowed backlight values
+     * Use the brightness minimum and maximum values to clamp these arrays.
+     */
+    private void constrainNitsAndBacklightArrays() {
+        if (mRawBacklight[0] > mBacklightMinimum
+                || mRawBacklight[mRawBacklight.length - 1] < mBacklightMaximum
+                || mBacklightMinimum > mBacklightMaximum) {
+            throw new IllegalStateException("Min or max values are invalid"
+                    + "; raw min=" + mRawBacklight[0]
+                    + "; raw max=" + mRawBacklight[mRawBacklight.length - 1]
+                    + "; backlight min=" + mBacklightMinimum
+                    + "; backlight max=" + mBacklightMaximum);
+        }
+
+        float[] newNits = new float[mRawBacklight.length];
+        float[] newBacklight = new float[mRawBacklight.length];
+        // Find the starting index of the clamped arrays. This may be less than the min so
+        // we'll need to clamp this value still when actually doing the remapping.
+        int newStart = 0;
+        for (int i = 0; i < mRawBacklight.length - 1; i++) {
+            if (mRawBacklight[i + 1] > mBacklightMinimum) {
+                newStart = i;
+                break;
+            }
+        }
+
+        boolean isLastValue = false;
+        int newIndex = 0;
+        for (int i = newStart; i < mRawBacklight.length && !isLastValue; i++) {
+            newIndex = i - newStart;
+            final float newBacklightVal;
+            final float newNitsVal;
+            isLastValue = mRawBacklight[i] > mBacklightMaximum
+                    || i >= mRawBacklight.length - 1;
+            // Clamp beginning and end to valid backlight values.
+            if (newIndex == 0) {
+                newBacklightVal = MathUtils.max(mRawBacklight[i], mBacklightMinimum);
+                newNitsVal = rawBacklightToNits(i, newBacklightVal);
+            } else if (isLastValue) {
+                newBacklightVal = MathUtils.min(mRawBacklight[i], mBacklightMaximum);
+                newNitsVal = rawBacklightToNits(i - 1, newBacklightVal);
+            } else {
+                newBacklightVal = mRawBacklight[i];
+                newNitsVal = mRawNits[i];
+            }
+            newBacklight[newIndex] = newBacklightVal;
+            newNits[newIndex] = newNitsVal;
+        }
+        mBacklight = Arrays.copyOf(newBacklight, newIndex + 1);
+        mNits = Arrays.copyOf(newNits, newIndex + 1);
+        createBacklightConversionSplines();
+    }
+
+    private float rawBacklightToNits(int i, float backlight) {
+        return MathUtils.map(mRawBacklight[i], mRawBacklight[i + 1],
+                mRawNits[i], mRawNits[i + 1], backlight);
+    }
+
+    // This method creates a brightness spline that is of equal length with proportional increments
+    // to the backlight spline. The values of this array range from 0.0f to 1.0f instead of the
+    // potential constrained range that the backlight array covers
+    // These splines are used to convert from the system brightness value to the HAL backlight
+    // value
+    private void createBacklightConversionSplines() {
+        mBrightness = new float[mBacklight.length];
+        for (int i = 0; i < mBrightness.length; i++) {
+            mBrightness[i] = MathUtils.map(mBacklight[0],
+                    mBacklight[mBacklight.length - 1],
+                    PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, mBacklight[i]);
+        }
+        mBrightnessToBacklightSpline = Spline.createSpline(mBrightness, mBacklight);
+        mBacklightToBrightnessSpline = Spline.createSpline(mBacklight, mBrightness);
     }
 
     private void loadQuirks(DisplayConfiguration config) {
@@ -425,12 +587,14 @@
             mIsHighBrightnessModeEnabled = hbm.getEnabled();
             mHbmData = new HighBrightnessModeData();
             mHbmData.minimumLux = hbm.getMinimumLux_all().floatValue();
-            mHbmData.transitionPoint = hbm.getTransitionPoint_all().floatValue();
-            if (mHbmData.transitionPoint >= getMaxBrightness()) {
+            float transitionPointBacklightScale = hbm.getTransitionPoint_all().floatValue();
+            if (transitionPointBacklightScale >= mBacklightMaximum) {
                 throw new IllegalArgumentException("HBM transition point invalid. "
                         + mHbmData.transitionPoint + " is not less than "
-                        + getMaxBrightness());
+                        + mBacklightMaximum);
             }
+            mHbmData.transitionPoint =
+                    mBacklightToBrightnessSpline.interpolate(transitionPointBacklightScale);
             final HbmTiming hbmTiming = hbm.getTiming_all();
             mHbmData.timeWindowMillis = hbmTiming.getTimeWindowSecs_all().longValue() * 1000;
             mHbmData.timeMaxMillis = hbmTiming.getTimeMaxSecs_all().longValue() * 1000;
diff --git a/services/core/java/com/android/server/display/DisplayGroup.java b/services/core/java/com/android/server/display/DisplayGroup.java
index 663883a..2dcd5cc 100644
--- a/services/core/java/com/android/server/display/DisplayGroup.java
+++ b/services/core/java/com/android/server/display/DisplayGroup.java
@@ -30,6 +30,8 @@
     private final List<LogicalDisplay> mDisplays = new ArrayList<>();
     private final int mGroupId;
 
+    private int mChangeCount;
+
     DisplayGroup(int groupId) {
         mGroupId = groupId;
     }
@@ -45,11 +47,16 @@
      * @param display the {@link LogicalDisplay} to add to the Group
      */
     void addDisplayLocked(LogicalDisplay display) {
-        if (!mDisplays.contains(display)) {
+        if (!containsLocked(display)) {
+            mChangeCount++;
             mDisplays.add(display);
         }
     }
 
+    boolean containsLocked(LogicalDisplay display) {
+        return mDisplays.contains(display);
+    }
+
     /**
      * Removes the provided {@code display} from the Group.
      *
@@ -57,6 +64,7 @@
      * @return {@code true} if the {@code display} was removed; otherwise {@code false}
      */
     boolean removeDisplayLocked(LogicalDisplay display) {
+        mChangeCount++;
         return mDisplays.remove(display);
     }
 
@@ -65,6 +73,11 @@
         return mDisplays.isEmpty();
     }
 
+    /** Returns a count of the changes made to this display group. */
+    int getChangeCountLocked() {
+        return mChangeCount;
+    }
+
     /** Returns the number of {@link LogicalDisplay LogicalDisplays} in the Group. */
     int getSizeLocked() {
         return mDisplays.size();
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index c62dd72..174d4b2 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -423,7 +423,7 @@
         mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper());
         mUiHandler = UiThread.getHandler();
         mDisplayDeviceRepo = new DisplayDeviceRepository(mSyncRoot, mPersistentDataStore);
-        mLogicalDisplayMapper = new LogicalDisplayMapper(context, mDisplayDeviceRepo,
+        mLogicalDisplayMapper = new LogicalDisplayMapper(mDisplayDeviceRepo,
                 new LogicalDisplayListener());
         mDisplayModeDirector = new DisplayModeDirector(context, mHandler);
         mBrightnessSynchronizer = new BrightnessSynchronizer(mContext);
@@ -485,13 +485,13 @@
             synchronized (mSyncRoot) {
                 long timeout = SystemClock.uptimeMillis()
                         + mInjector.getDefaultDisplayDelayTimeout();
-                while (mLogicalDisplayMapper.getLocked(Display.DEFAULT_DISPLAY) == null
+                while (mLogicalDisplayMapper.getDisplayLocked(Display.DEFAULT_DISPLAY) == null
                         || mVirtualDisplayAdapter == null) {
                     long delay = timeout - SystemClock.uptimeMillis();
                     if (delay <= 0) {
                         throw new RuntimeException("Timeout waiting for default display "
                                 + "to be initialized. DefaultDisplay="
-                                + mLogicalDisplayMapper.getLocked(Display.DEFAULT_DISPLAY)
+                                + mLogicalDisplayMapper.getDisplayLocked(Display.DEFAULT_DISPLAY)
                                 + ", mVirtualDisplayAdapter=" + mVirtualDisplayAdapter);
                     }
                     if (DEBUG) {
@@ -532,7 +532,7 @@
 
             DeviceStateManager deviceStateManager =
                     mContext.getSystemService(DeviceStateManager.class);
-            deviceStateManager.addDeviceStateListener(new HandlerExecutor(mHandler),
+            deviceStateManager.registerCallback(new HandlerExecutor(mHandler),
                     new DeviceStateListener());
 
             scheduleTraversalLocked(false);
@@ -549,7 +549,7 @@
             mSystemReady = true;
             // Just in case the top inset changed before the system was ready. At this point, any
             // relevant configuration should be in place.
-            recordTopInsetLocked(mLogicalDisplayMapper.getLocked(Display.DEFAULT_DISPLAY));
+            recordTopInsetLocked(mLogicalDisplayMapper.getDisplayLocked(Display.DEFAULT_DISPLAY));
 
             updateSettingsLocked();
         }
@@ -617,7 +617,7 @@
     @VisibleForTesting
     void setDisplayInfoOverrideFromWindowManagerInternal(int displayId, DisplayInfo info) {
         synchronized (mSyncRoot) {
-            LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
+            final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
             if (display != null) {
                 if (display.setDisplayInfoOverrideFromWindowManagerLocked(info)) {
                     handleLogicalDisplayChangedLocked(display);
@@ -632,7 +632,7 @@
      */
     private void getNonOverrideDisplayInfoInternal(int displayId, DisplayInfo outInfo) {
         synchronized (mSyncRoot) {
-            final LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
+            final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
             if (display != null) {
                 display.getNonOverrideDisplayInfoLocked(outInfo);
             }
@@ -691,8 +691,8 @@
 
             mDisplayStates.setValueAt(index, state);
             mDisplayBrightnesses.setValueAt(index, brightnessState);
-            runnable = updateDisplayStateLocked(
-                    mLogicalDisplayMapper.getLocked(displayId).getPrimaryDisplayDeviceLocked());
+            runnable = updateDisplayStateLocked(mLogicalDisplayMapper.getDisplayLocked(displayId)
+                    .getPrimaryDisplayDeviceLocked());
         }
 
         // Setting the display power state can take hundreds of milliseconds
@@ -803,9 +803,9 @@
 
     private DisplayInfo getDisplayInfoInternal(int displayId, int callingUid) {
         synchronized (mSyncRoot) {
-            LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
+            final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
             if (display != null) {
-                DisplayInfo info =
+                final DisplayInfo info =
                         getDisplayInfoForFrameRateOverride(display.getFrameRateOverrides(),
                                 display.getDisplayInfoLocked(), callingUid);
                 if (info.hasAccess(callingUid)
@@ -952,7 +952,7 @@
 
     private void requestColorModeInternal(int displayId, int colorMode) {
         synchronized (mSyncRoot) {
-            LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
+            final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
             if (display != null &&
                     display.getRequestedColorModeLocked() != colorMode) {
                 display.setRequestedColorModeLocked(colorMode);
@@ -989,7 +989,7 @@
             mDisplayDeviceRepo.onDisplayDeviceEvent(device,
                     DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED);
 
-            LogicalDisplay display = mLogicalDisplayMapper.getLocked(device);
+            final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
             if (display != null) {
                 return display.getDisplayIdLocked();
             }
@@ -1178,7 +1178,10 @@
 
     private void handleLogicalDisplayRemovedLocked(@NonNull LogicalDisplay display) {
         final int displayId = display.getDisplayIdLocked();
-        mDisplayPowerControllers.removeReturnOld(displayId).stop();
+        final DisplayPowerController dpc = mDisplayPowerControllers.removeReturnOld(displayId);
+        if (dpc != null) {
+            dpc.stop();
+        }
         mDisplayStates.delete(displayId);
         mDisplayBrightnesses.delete(displayId);
         DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
@@ -1200,10 +1203,7 @@
         // by the display power controller (if known).
         DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
         if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
-            // TODO - b/170498827 The rules regarding what display state to apply to each
-            // display will depend on the configuration/mapping of logical displays.
-            // Clean up LogicalDisplay.isEnabled() mechanism once this is fixed.
-            final LogicalDisplay display = mLogicalDisplayMapper.getLocked(device);
+            final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
             final int state;
             final int displayId = display.getDisplayIdLocked();
 
@@ -1364,7 +1364,7 @@
             float requestedRefreshRate, int requestedModeId, boolean preferMinimalPostProcessing,
             boolean inTraversal) {
         synchronized (mSyncRoot) {
-            LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
+            final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
             if (display == null) {
                 return;
             }
@@ -1406,7 +1406,7 @@
 
     private void setDisplayOffsetsInternal(int displayId, int x, int y) {
         synchronized (mSyncRoot) {
-            LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
+            final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
             if (display == null) {
                 return;
             }
@@ -1424,7 +1424,7 @@
 
     private void setDisplayScalingDisabledInternal(int displayId, boolean disable) {
         synchronized (mSyncRoot) {
-            final LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
+            final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
             if (display == null) {
                 return;
             }
@@ -1460,7 +1460,7 @@
     @Nullable
     private IBinder getDisplayToken(int displayId) {
         synchronized (mSyncRoot) {
-            final LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
+            final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
             if (display != null) {
                 final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
                 if (device != null) {
@@ -1478,7 +1478,7 @@
             if (token == null) {
                 return null;
             }
-            final LogicalDisplay logicalDisplay = mLogicalDisplayMapper.getLocked(displayId);
+            final LogicalDisplay logicalDisplay = mLogicalDisplayMapper.getDisplayLocked(displayId);
             if (logicalDisplay == null) {
                 return null;
             }
@@ -1611,15 +1611,16 @@
 
         // Find the logical display that the display device is showing.
         // Certain displays only ever show their own content.
-        LogicalDisplay display = mLogicalDisplayMapper.getLocked(device);
+        LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
         if (!ownContent) {
             if (display != null && !display.hasContentLocked()) {
                 // If the display does not have any content of its own, then
                 // automatically mirror the requested logical display contents if possible.
-                display = mLogicalDisplayMapper.getLocked(device.getDisplayIdToMirrorLocked());
+                display = mLogicalDisplayMapper.getDisplayLocked(
+                        device.getDisplayIdToMirrorLocked());
             }
             if (display == null) {
-                display = mLogicalDisplayMapper.getLocked(Display.DEFAULT_DISPLAY);
+                display = mLogicalDisplayMapper.getDisplayLocked(Display.DEFAULT_DISPLAY);
             }
         }
 
@@ -1896,9 +1897,9 @@
     @VisibleForTesting
     DisplayDeviceInfo getDisplayDeviceInfoInternal(int displayId) {
         synchronized (mSyncRoot) {
-            LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
+            final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
             if (display != null) {
-                DisplayDevice displayDevice = display.getPrimaryDisplayDeviceLocked();
+                final DisplayDevice displayDevice = display.getPrimaryDisplayDeviceLocked();
                 return displayDevice.getDisplayDeviceInfoLocked();
             }
             return null;
@@ -1908,9 +1909,9 @@
     @VisibleForTesting
     int getDisplayIdToMirrorInternal(int displayId) {
         synchronized (mSyncRoot) {
-            LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
+            final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
             if (display != null) {
-                DisplayDevice displayDevice = display.getPrimaryDisplayDeviceLocked();
+                final DisplayDevice displayDevice = display.getPrimaryDisplayDeviceLocked();
                 return displayDevice.getDisplayIdToMirrorLocked();
             }
             return Display.INVALID_DISPLAY;
@@ -1992,7 +1993,8 @@
                     ArraySet<Integer> uids;
                     synchronized (mSyncRoot) {
                         int displayId = msg.arg1;
-                        LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
+                        final LogicalDisplay display =
+                                mLogicalDisplayMapper.getDisplayLocked(displayId);
                         uids = display.getPendingFrameRateOverrideUids();
                         display.clearPendingFrameRateOverrideUids();
                     }
@@ -2586,7 +2588,7 @@
         @Override // Binder call
         public boolean isMinimalPostProcessingRequested(int displayId) {
             synchronized (mSyncRoot) {
-                return mLogicalDisplayMapper.getLocked(displayId)
+                return mLogicalDisplayMapper.getDisplayLocked(displayId)
                         .getRequestedMinimalPostProcessingLocked();
             }
         }
@@ -2831,7 +2833,7 @@
         @Override
         public Point getDisplayPosition(int displayId) {
             synchronized (mSyncRoot) {
-                LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
+                final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
                 if (display != null) {
                     return display.getDisplayPosition();
                 }
@@ -2974,9 +2976,9 @@
     /**
      * Listens to changes in device state and reports the state to LogicalDisplayMapper.
      */
-    class DeviceStateListener implements DeviceStateManager.DeviceStateListener {
+    class DeviceStateListener implements DeviceStateManager.DeviceStateCallback {
         @Override
-        public void onDeviceStateChanged(int deviceState) {
+        public void onStateChanged(int deviceState) {
             synchronized (mSyncRoot) {
                 mLogicalDisplayMapper.setDeviceStateLocked(deviceState);
             }
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index dce6bd8..645ca7a 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -31,7 +31,6 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
@@ -80,6 +79,8 @@
     // specific display.
     private static final int GLOBAL_ID = -1;
 
+    private static final int INVALID_DISPLAY_MODE_ID = -1;
+
     // The tolerance within which we consider something approximately equals.
     private static final float FLOAT_TOLERANCE = 0.01f;
 
@@ -322,12 +323,30 @@
                                 appRequestSummary.maxRefreshRate));
             }
 
-            // If the application requests a given mode with preferredModeId function, it will be
-            // stored as baseModeId.
-            int baseModeId = defaultMode.getModeId();
-            if (availableModes.length > 0) {
+            int baseModeId = INVALID_DISPLAY_MODE_ID;
+
+            // Select the default mode if available. This is important because SurfaceFlinger
+            // can do only seamless switches by default. Some devices (e.g. TV) don't support
+            // seamless switching so the mode we select here won't be changed.
+            for (int availableMode : availableModes) {
+                if (availableMode == defaultMode.getModeId()) {
+                    baseModeId = defaultMode.getModeId();
+                    break;
+                }
+            }
+
+            // If the application requests a display mode by setting
+            // LayoutParams.preferredDisplayModeId, it will be the only available mode and it'll
+            // be stored as baseModeId.
+            if (baseModeId == INVALID_DISPLAY_MODE_ID && availableModes.length > 0) {
                 baseModeId = availableModes[0];
             }
+
+            if (baseModeId == INVALID_DISPLAY_MODE_ID) {
+                throw new IllegalStateException("Can't select a base display mode for display "
+                        + displayId + ". The votes are " + mVotesByDisplay.valueAt(displayId));
+            }
+
             if (mModeSwitchingType == DisplayManager.SWITCHING_TYPE_NONE) {
                 Display.Mode baseMode = null;
                 for (Display.Mode mode : modes) {
@@ -351,6 +370,7 @@
 
             boolean allowGroupSwitching =
                     mModeSwitchingType == DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS;
+
             return new DesiredDisplayModeSpecs(baseModeId,
                     allowGroupSwitching,
                     new RefreshRateRange(
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 62cf86b..0117326 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -190,12 +190,6 @@
     // The dim screen brightness.
     private final float mScreenBrightnessDimConfig;
 
-    // The minimum allowed brightness.
-    private final float mScreenBrightnessRangeMinimum;
-
-    // The maximum allowed brightness.
-    private final float mScreenBrightnessRangeMaximum;
-
     private final float mScreenBrightnessDefault;
 
     // The minimum allowed brightness while in VR.
@@ -443,8 +437,6 @@
 
         final Resources resources = context.getResources();
 
-        final float screenBrightnessSettingMinimumFloat = clampAbsoluteBrightness(
-                pm.getBrightnessConstraint(PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM));
 
         // DOZE AND DIM SETTINGS
         mScreenBrightnessDozeConfig = clampAbsoluteBrightness(
@@ -453,10 +445,6 @@
                 pm.getBrightnessConstraint(PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_DIM));
 
         // NORMAL SCREEN SETTINGS
-        mScreenBrightnessRangeMinimum =
-                Math.min(screenBrightnessSettingMinimumFloat, mScreenBrightnessDimConfig);
-        mScreenBrightnessRangeMaximum = clampAbsoluteBrightness(
-                pm.getBrightnessConstraint(PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM));
         mScreenBrightnessDefault = clampAbsoluteBrightness(
                 mLogicalDisplay.getDisplayInfoLocked().brightnessDefault);
 
@@ -481,18 +469,10 @@
 
         DisplayDeviceConfig displayDeviceConfig = logicalDisplay
                 .getPrimaryDisplayDeviceLocked().getDisplayDeviceConfig();
-        // TODO: (b/178183143) Ensure that the ddc is not null
-        if (displayDeviceConfig != null) {
-            mBrightnessRampRateFastDecrease = displayDeviceConfig.getBrightnessRampFastDecrease();
-            mBrightnessRampRateFastIncrease = displayDeviceConfig.getBrightnessRampFastIncrease();
-            mBrightnessRampRateSlowDecrease = displayDeviceConfig.getBrightnessRampSlowDecrease();
-            mBrightnessRampRateSlowIncrease = displayDeviceConfig.getBrightnessRampSlowIncrease();
-        } else {
-            mBrightnessRampRateFastDecrease = 1.0f;
-            mBrightnessRampRateFastIncrease = 1.0f;
-            mBrightnessRampRateSlowDecrease = 1.0f;
-            mBrightnessRampRateSlowIncrease = 1.0f;
-        }
+        mBrightnessRampRateFastDecrease = displayDeviceConfig.getBrightnessRampFastDecrease();
+        mBrightnessRampRateFastIncrease = displayDeviceConfig.getBrightnessRampFastIncrease();
+        mBrightnessRampRateSlowDecrease = displayDeviceConfig.getBrightnessRampSlowDecrease();
+        mBrightnessRampRateSlowIncrease = displayDeviceConfig.getBrightnessRampSlowIncrease();
         mSkipScreenOnBrightnessRamp = resources.getBoolean(
                 com.android.internal.R.bool.config_skipScreenOnBrightnessRamp);
 
@@ -545,12 +525,14 @@
                     com.android.internal.R.string.config_displayLightSensorType);
             Sensor lightSensor = findDisplayLightSensor(lightSensorType);
 
-            mBrightnessMapper = BrightnessMappingStrategy.create(resources);
+            final DisplayDeviceConfig ddc =
+                    logicalDisplay.getPrimaryDisplayDeviceLocked().getDisplayDeviceConfig();
+            mBrightnessMapper = BrightnessMappingStrategy.create(resources, ddc);
             if (mBrightnessMapper != null) {
                 mAutomaticBrightnessController = new AutomaticBrightnessController(this,
                         handler.getLooper(), sensorManager, lightSensor, mBrightnessMapper,
-                        lightSensorWarmUpTimeConfig, mScreenBrightnessRangeMinimum,
-                        mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
+                        lightSensorWarmUpTimeConfig, PowerManager.BRIGHTNESS_MIN,
+                        PowerManager.BRIGHTNESS_MAX, dozeScaleFactor, lightSensorRate,
                         initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
                         autoBrightnessResetAmbientLuxAfterWarmUp, ambientBrightnessThresholds,
                         screenBrightnessThresholds, logicalDisplay, context);
@@ -838,9 +820,8 @@
         noteScreenBrightness(mPowerState.getScreenBrightness());
 
         // Initialize all of the brightness tracking state
-        final float brightness = convertToNits(BrightnessSynchronizer.brightnessFloatToInt(
-                mPowerState.getScreenBrightness()));
-        if (brightness >= 0.0f) {
+        final float brightness = convertToNits(mPowerState.getScreenBrightness());
+        if (brightness >= PowerManager.BRIGHTNESS_MIN) {
             mBrightnessTracker.start(brightness);
         }
 
@@ -877,8 +858,10 @@
     private void cleanupHandlerThreadAfterStop() {
         setProximitySensorEnabled(false);
         mHandler.removeCallbacksAndMessages(null);
-        mPowerState.stop();
-        mPowerState = null;
+        if (mPowerState != null) {
+            mPowerState.stop();
+            mPowerState = null;
+        }
     }
 
     private void updatePowerState() {
@@ -1151,10 +1134,10 @@
         // Apply dimming by at least some minimum amount when user activity
         // timeout is about to expire.
         if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
-            if (brightnessState > mScreenBrightnessRangeMinimum) {
+            if (brightnessState > PowerManager.BRIGHTNESS_MIN) {
                 brightnessState = Math.max(Math.min(brightnessState
                                 - SCREEN_DIM_MINIMUM_REDUCTION_FLOAT,
-                        mScreenBrightnessDimConfig), mScreenBrightnessRangeMinimum);
+                        mScreenBrightnessDimConfig), PowerManager.BRIGHTNESS_MIN);
                 mBrightnessReasonTemp.addModifier(BrightnessReason.MODIFIER_DIMMED);
             }
             if (!mAppliedDimming) {
@@ -1168,12 +1151,11 @@
         // If low power mode is enabled, scale brightness by screenLowPowerBrightnessFactor
         // as long as it is above the minimum threshold.
         if (mPowerRequest.lowPowerMode) {
-            if (brightnessState > mScreenBrightnessRangeMinimum) {
+            if (brightnessState > PowerManager.BRIGHTNESS_MIN) {
                 final float brightnessFactor =
                         Math.min(mPowerRequest.screenLowPowerBrightnessFactor, 1);
                 final float lowPowerBrightnessFloat = (brightnessState * brightnessFactor);
-                brightnessState = Math.max(lowPowerBrightnessFloat,
-                        mScreenBrightnessRangeMinimum);
+                brightnessState = Math.max(lowPowerBrightnessFloat, PowerManager.BRIGHTNESS_MIN);
                 mBrightnessReasonTemp.addModifier(BrightnessReason.MODIFIER_LOW_POWER);
             }
             if (!mAppliedLowPower) {
@@ -1258,9 +1240,8 @@
                     // slider event so notify as if the system changed the brightness.
                     userInitiatedChange = false;
                 }
-                notifyBrightnessChanged(
-                        BrightnessSynchronizer.brightnessFloatToInt(brightnessState),
-                        userInitiatedChange, hadUserBrightnessPoint);
+                notifyBrightnessChanged(brightnessState, userInitiatedChange,
+                        hadUserBrightnessPoint);
             }
 
         }
@@ -1487,17 +1468,17 @@
 
     private float clampScreenBrightness(float value) {
         if (Float.isNaN(value)) {
-            return mScreenBrightnessRangeMinimum;
+            return PowerManager.BRIGHTNESS_MIN;
         }
         return MathUtils.constrain(
-                value, mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
+                value, PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX);
     }
 
     // Checks whether the brightness is within the valid brightness range, not including the off or
     // invalid states.
     private boolean isValidBrightnessValue(float brightnessState) {
-        return brightnessState >= mScreenBrightnessRangeMinimum
-                && brightnessState <= mScreenBrightnessRangeMaximum;
+        return brightnessState >= PowerManager.BRIGHTNESS_MIN
+                && brightnessState <= PowerManager.BRIGHTNESS_MAX;
     }
 
     private void animateScreenBrightness(float target, float rate) {
@@ -1874,7 +1855,7 @@
         return true;
     }
 
-    private void notifyBrightnessChanged(int brightness, boolean userInitiated,
+    private void notifyBrightnessChanged(float brightness, boolean userInitiated,
             boolean hadUserDataPoint) {
         final float brightnessInNits = convertToNits(brightness);
         if (mPowerRequest.useAutoBrightness && brightnessInNits >= 0.0f
@@ -1891,9 +1872,9 @@
         }
     }
 
-    private float convertToNits(int backlight) {
+    private float convertToNits(float brightness) {
         if (mBrightnessMapper != null) {
-            return mBrightnessMapper.convertToNits(backlight);
+            return mBrightnessMapper.convertToNits(brightness);
         } else {
             return -1.0f;
         }
@@ -1972,12 +1953,9 @@
 
         pw.println();
         pw.println("Display Power Controller Configuration:");
-        pw.println("  mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
-        pw.println("  mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
         pw.println("  mScreenBrightnessRangeDefault=" + mScreenBrightnessDefault);
         pw.println("  mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig);
         pw.println("  mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
-        pw.println("  mScreenBrightnessDefault=" + mScreenBrightnessDefault);
         pw.println("  mScreenBrightnessForVrRangeMinimum=" + mScreenBrightnessForVrRangeMinimum);
         pw.println("  mScreenBrightnessForVrRangeMaximum=" + mScreenBrightnessForVrRangeMaximum);
         pw.println("  mScreenBrightnessForVrDefault=" + mScreenBrightnessForVrDefault);
@@ -2109,10 +2087,6 @@
         }
     }
 
-    private static int clampAbsoluteBrightness(int value) {
-        return MathUtils.constrain(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
-    }
-
     private static float clampAbsoluteBrightness(float value) {
         return MathUtils.constrain(value, PowerManager.BRIGHTNESS_MIN,
                 PowerManager.BRIGHTNESS_MAX);
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 5b2b336..3709963 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -30,7 +30,6 @@
 import android.util.LongSparseArray;
 import android.util.Slog;
 import android.util.SparseArray;
-import android.util.Spline;
 import android.view.Display;
 import android.view.DisplayAddress;
 import android.view.DisplayCutout;
@@ -210,8 +209,7 @@
         private SurfaceControl.DisplayMode[] mSfDisplayModes;
         // The active display mode in SurfaceFlinger
         private SurfaceControl.DisplayMode mActiveSfDisplayMode;
-        private Spline mSystemBrightnessToNits;
-        private Spline mNitsToHalBrightness;
+        private DisplayDeviceConfig mDisplayDeviceConfig;
 
         private DisplayEventReceiver.FrameRateOverride[] mFrameRateOverrides =
                 new DisplayEventReceiver.FrameRateOverride[0];
@@ -410,16 +408,13 @@
         @Override
         public DisplayDeviceConfig getDisplayDeviceConfig() {
             if (mDisplayDeviceConfig == null) {
-                loadDisplayConfiguration();
+                loadDisplayDeviceConfig();
             }
             return mDisplayDeviceConfig;
         }
 
-        private void loadDisplayConfiguration() {
-            Spline nitsToHal = null;
-            Spline sysToNits = null;
-
-            // Load the mapping from nits to HAL brightness range (display-device-config.xml)
+        private void loadDisplayDeviceConfig() {
+            // Load display device config
             final Context context = getOverlayContext();
             mDisplayDeviceConfig = DisplayDeviceConfig.create(context, mPhysicalDisplayId,
                     mIsDefaultDisplay);
@@ -427,33 +422,9 @@
                 return;
             }
 
+            // Load brightness HWC quirk
             mBacklightAdapter.setForceSurfaceControl(mDisplayDeviceConfig.hasQuirk(
                     DisplayDeviceConfig.QUIRK_CAN_SET_BRIGHTNESS_VIA_HWC));
-
-            final float[] halNits = mDisplayDeviceConfig.getNits();
-            final float[] halBrightness = mDisplayDeviceConfig.getBrightness();
-            if (halNits == null || halBrightness == null) {
-                return;
-            }
-            nitsToHal = Spline.createSpline(halNits, halBrightness);
-
-            // Load the mapping from system brightness range to nits (config.xml)
-            final Resources res = context.getResources();
-            final float[] sysNits = BrightnessMappingStrategy.getFloatArray(res.obtainTypedArray(
-                    com.android.internal.R.array.config_screenBrightnessNits));
-            final int[] sysBrightness = res.getIntArray(
-                    com.android.internal.R.array.config_screenBrightnessBacklight);
-            if (sysNits.length == 0 || sysBrightness.length != sysNits.length) {
-                return;
-            }
-            final float[] sysBrightnessFloat = new float[sysBrightness.length];
-            for (int i = 0; i < sysBrightness.length; i++) {
-                sysBrightnessFloat[i] = sysBrightness[i];
-            }
-            sysToNits = Spline.createSpline(sysBrightnessFloat, sysNits);
-
-            mNitsToHalBrightness = nitsToHal;
-            mSystemBrightnessToNits = sysToNits;
         }
 
         private boolean updateStaticInfo(SurfaceControl.StaticDisplayInfo info) {
@@ -665,15 +636,9 @@
 
                 // The display is trusted since it is created by system.
                 mInfo.flags |= DisplayDeviceInfo.FLAG_TRUSTED;
-                if (mDisplayDeviceConfig != null) {
-                    mInfo.brightnessMinimum = mDisplayDeviceConfig.getBrightnessMinimum();
-                    mInfo.brightnessMaximum = mDisplayDeviceConfig.getBrightnessMaximum();
-                    mInfo.brightnessDefault = mDisplayDeviceConfig.getBrightnessDefault();
-                } else {
-                    mInfo.brightnessMinimum = PowerManager.BRIGHTNESS_MIN;
-                    mInfo.brightnessMaximum = PowerManager.BRIGHTNESS_MAX;
-                    mInfo.brightnessDefault = 0.5f;
-                }
+                mInfo.brightnessMinimum = PowerManager.BRIGHTNESS_MIN;
+                mInfo.brightnessMaximum = PowerManager.BRIGHTNESS_MAX;
+                mInfo.brightnessDefault = getDisplayDeviceConfig().getBrightnessDefault();
             }
             return mInfo;
         }
@@ -811,8 +776,8 @@
                         Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayBrightness("
                                 + "id=" + physicalDisplayId + ", brightness=" + brightness + ")");
                         try {
-                            brightness = displayBrightnessToHalBrightness(brightness);
-                            mBacklightAdapter.setBrightness(brightness);
+                            float backlight = brightnessToBacklight(brightness);
+                            mBacklightAdapter.setBacklight(backlight);
                             Trace.traceCounter(Trace.TRACE_TAG_POWER,
                                     "ScreenBrightness",
                                     BrightnessSynchronizer.brightnessFloatToInt(brightness));
@@ -821,35 +786,8 @@
                         }
                     }
 
-                    /**
-                     * Converts brightness range from the framework's brightness space to the
-                     * Hal brightness space if the HAL brightness space has been provided via
-                     * a display device configuration file.
-                     */
-                    private float displayBrightnessToHalBrightness(float brightness) {
-                        // TODO: b/171380847 - This needs to be deprecated. The nits-to-brightness
-                        // relationship should be specified in display-config OR config.xml, but not
-                        // both, and no nits-space conversion should be necessary.
-                        //
-                        // Only do a conversion if there exists a unique system brightness and a
-                        // unique HAL brightness-to-nits range defined.
-                        if (mSystemBrightnessToNits == null || mNitsToHalBrightness == null) {
-                            return brightness;
-                        }
-
-                        // Sys brightness in this conversion is always specified in the old 1-255
-                        // range, so convert that here before the translation.
-                        final float brightnessInt =
-                                BrightnessSynchronizer.brightnessFloatToIntRange(brightness);
-
-                        if (BrightnessSynchronizer.floatEquals(
-                                brightnessInt, PowerManager.BRIGHTNESS_OFF)) {
-                            return PowerManager.BRIGHTNESS_OFF_FLOAT;
-                        }
-
-                        final float nits = mSystemBrightnessToNits.interpolate(brightnessInt);
-                        final float halBrightness = mNitsToHalBrightness.interpolate(nits);
-                        return halBrightness;
+                    private float brightnessToBacklight(float brightness) {
+                        return getDisplayDeviceConfig().getBacklightFromBrightness(brightness);
                     }
                 };
             }
@@ -1338,11 +1276,12 @@
             }
         }
 
-        void setBrightness(float brightness) {
+        // Set backlight within min and max backlight values
+        void setBacklight(float backlight) {
             if (mUseSurfaceControlBrightness || mForceSurfaceControl) {
-                mSurfaceControlProxy.setDisplayBrightness(mDisplayToken, brightness);
+                mSurfaceControlProxy.setDisplayBrightness(mDisplayToken, backlight);
             } else if (mBacklight != null) {
-                mBacklight.setBrightness(brightness);
+                mBacklight.setBrightness(backlight);
             }
         }
 
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 20b133c..d9570c7 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -17,11 +17,11 @@
 package com.android.server.display;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManagerInternal;
 import android.util.ArraySet;
-import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
 import android.view.DisplayEventReceiver;
@@ -64,12 +64,14 @@
  */
 final class LogicalDisplay {
     private static final String TAG = "LogicalDisplay";
-    private final DisplayInfo mBaseDisplayInfo = new DisplayInfo();
 
     // The layer stack we use when the display has been blanked to prevent any
     // of its content from appearing.
     private static final int BLANK_LAYER_STACK = -1;
 
+    private static final DisplayInfo EMPTY_DISPLAY_INFO = new DisplayInfo();
+
+    private final DisplayInfo mBaseDisplayInfo = new DisplayInfo();
     private final int mDisplayId;
     private final int mLayerStack;
 
@@ -297,7 +299,7 @@
 
         // Check whether logical display has become invalid.
         if (!deviceRepo.containsLocked(mPrimaryDisplayDevice)) {
-            mPrimaryDisplayDevice = null;
+            setPrimaryDisplayDeviceLocked(null);
             return;
         }
 
@@ -684,18 +686,28 @@
      * @param targetDisplay The display with which to swap display-devices.
      * @return {@code true} if the displays were swapped, {@code false} otherwise.
      */
-    public boolean swapDisplaysLocked(@NonNull LogicalDisplay targetDisplay) {
-        final DisplayDevice targetDevice = targetDisplay.getPrimaryDisplayDeviceLocked();
-        if (mPrimaryDisplayDevice == null || targetDevice == null) {
-            Slog.e(TAG, "Missing display device during swap: " + mPrimaryDisplayDevice + " , "
-                    + targetDevice);
-            return false;
-        }
+    public void swapDisplaysLocked(@NonNull LogicalDisplay targetDisplay) {
+        final DisplayDevice oldTargetDevice =
+                targetDisplay.setPrimaryDisplayDeviceLocked(mPrimaryDisplayDevice);
+        setPrimaryDisplayDeviceLocked(oldTargetDevice);
+    }
 
-        final DisplayDevice tmpDevice = mPrimaryDisplayDevice;
-        mPrimaryDisplayDevice = targetDisplay.mPrimaryDisplayDevice;
-        targetDisplay.mPrimaryDisplayDevice = tmpDevice;
-        return true;
+    /**
+     * Sets the primary display device to the specified device.
+     *
+     * @param device The new device to set.
+     * @return The previously set display device.
+     */
+    public DisplayDevice setPrimaryDisplayDeviceLocked(@Nullable DisplayDevice device) {
+        final DisplayDevice old = mPrimaryDisplayDevice;
+        mPrimaryDisplayDevice = device;
+
+        // Reset all our display info data
+        mPrimaryDisplayDeviceInfo = null;
+        mBaseDisplayInfo.copyFrom(EMPTY_DISPLAY_INFO);
+        mInfo.set(null);
+
+        return old;
     }
 
     /**
@@ -718,8 +730,8 @@
 
     public void dumpLocked(PrintWriter pw) {
         pw.println("mDisplayId=" + mDisplayId);
-        pw.println("mLayerStack=" + mLayerStack);
         pw.println("mIsEnabled=" + mIsEnabled);
+        pw.println("mLayerStack=" + mLayerStack);
         pw.println("mHasContent=" + mHasContent);
         pw.println("mDesiredDisplayModeSpecs={" + mDesiredDisplayModeSpecs + "}");
         pw.println("mRequestedColorMode=" + mRequestedColorMode);
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index a3ff534..d6826be 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -16,14 +16,16 @@
 
 package com.android.server.display;
 
-import android.content.Context;
+import android.hardware.devicestate.DeviceStateManager;
 import android.os.SystemProperties;
 import android.text.TextUtils;
 import android.util.IndentingPrintWriter;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
 import android.view.Display;
-import android.view.DisplayEventReceiver;
+import android.view.DisplayAddress;
 import android.view.DisplayInfo;
 
 import com.android.server.display.layout.Layout;
@@ -74,49 +76,79 @@
     private final boolean mSingleDisplayDemoMode;
 
     /**
-     * List of all logical displays indexed by logical display id.
+     * Map of all logical displays indexed by logical display id.
      * Any modification to mLogicalDisplays must invalidate the DisplayManagerGlobal cache.
      * TODO: multi-display - Move the aforementioned comment?
      */
     private final SparseArray<LogicalDisplay> mLogicalDisplays =
             new SparseArray<LogicalDisplay>();
 
-    /** A mapping from logical display id to display group. */
-    private final SparseArray<DisplayGroup> mDisplayIdToGroupMap = new SparseArray<>();
+    /** Map of all display groups indexed by display group id. */
+    private final SparseArray<DisplayGroup> mDisplayGroups = new SparseArray<>();
 
     private final DisplayDeviceRepository mDisplayDeviceRepo;
     private final DeviceStateToLayoutMap mDeviceStateToLayoutMap;
     private final Listener mListener;
-    private final int[] mFoldedDeviceStates;
+
+    /**
+     * Has an entry for every logical display that the rest of the system has been notified about.
+     * Any entry in here requires us to send a {@link  LOGICAL_DISPLAY_EVENT_REMOVED} event when it
+     * is deleted or {@link  LOGICAL_DISPLAY_EVENT_CHANGED} when it is changed.
+     */
+    private final SparseBooleanArray mUpdatedLogicalDisplays = new SparseBooleanArray();
+
+    /**
+     * Keeps track of all the display groups that we already told other people about. IOW, if a
+     * display group is in this array, then we *must* send change and remove notifications for it
+     * because other components know about them. Also, what this array stores is a change counter
+     * for each group, so we know if the group itself has changes since we last sent out a
+     * notification.  See {@link DisplayGroup#getChangeCountLocked}.
+     */
+    private final SparseIntArray mUpdatedDisplayGroups = new SparseIntArray();
+
+    /**
+     * Array used in {@link #updateLogicalDisplaysLocked} to track events that need to be sent out.
+     */
+    private final SparseIntArray mLogicalDisplaysToUpdate = new SparseIntArray();
+
+    /**
+     * Array used in {@link #updateLogicalDisplaysLocked} to track events that need to be sent out.
+     */
+    private final SparseIntArray mDisplayGroupsToUpdate = new SparseIntArray();
 
     private int mNextNonDefaultGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
     private Layout mCurrentLayout = null;
-    private boolean mIsFolded = false;
+    private int mDeviceState = DeviceStateManager.INVALID_DEVICE_STATE;
 
-    LogicalDisplayMapper(Context context, DisplayDeviceRepository repo, Listener listener) {
+    LogicalDisplayMapper(DisplayDeviceRepository repo, Listener listener) {
         mDisplayDeviceRepo = repo;
         mListener = listener;
         mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
         mDisplayDeviceRepo.addListener(this);
-
-        mFoldedDeviceStates = context.getResources().getIntArray(
-                com.android.internal.R.array.config_foldedDeviceStates);
-
-        mDeviceStateToLayoutMap = new DeviceStateToLayoutMap(context);
+        mDeviceStateToLayoutMap = new DeviceStateToLayoutMap();
     }
 
     @Override
     public void onDisplayDeviceEventLocked(DisplayDevice device, int event) {
         switch (event) {
             case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_ADDED:
+                if (DEBUG) {
+                    Slog.d(TAG, "Display device added: " + device.getDisplayDeviceInfoLocked());
+                }
                 handleDisplayDeviceAddedLocked(device);
                 break;
 
             case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_CHANGED:
+                if (DEBUG) {
+                    Slog.d(TAG, "Display device changed: " + device.getDisplayDeviceInfoLocked());
+                }
                 updateLogicalDisplaysLocked();
                 break;
 
             case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_REMOVED:
+                if (DEBUG) {
+                    Slog.d(TAG, "Display device removed: " + device.getDisplayDeviceInfoLocked());
+                }
                 updateLogicalDisplaysLocked();
                 break;
         }
@@ -127,11 +159,11 @@
         mListener.onTraversalRequested();
     }
 
-    public LogicalDisplay getLocked(int displayId) {
+    public LogicalDisplay getDisplayLocked(int displayId) {
         return mLogicalDisplays.get(displayId);
     }
 
-    public LogicalDisplay getLocked(DisplayDevice device) {
+    public LogicalDisplay getDisplayLocked(DisplayDevice device) {
         final int count = mLogicalDisplays.size();
         for (int i = 0; i < count; i++) {
             LogicalDisplay display = mLogicalDisplays.valueAt(i);
@@ -166,16 +198,25 @@
         }
     }
 
-    public DisplayGroup getDisplayGroupLocked(int groupId) {
-        final int size = mDisplayIdToGroupMap.size();
+    public int getDisplayGroupIdFromDisplayIdLocked(int displayId) {
+        final LogicalDisplay display = getDisplayLocked(displayId);
+        if (display == null) {
+            return Display.INVALID_DISPLAY_GROUP;
+        }
+
+        final int size = mDisplayGroups.size();
         for (int i = 0; i < size; i++) {
-            final DisplayGroup displayGroup = mDisplayIdToGroupMap.valueAt(i);
-            if (displayGroup.getGroupId() == groupId) {
-                return displayGroup;
+            final DisplayGroup displayGroup = mDisplayGroups.valueAt(i);
+            if (displayGroup.containsLocked(display)) {
+                return mDisplayGroups.keyAt(i);
             }
         }
 
-        return null;
+        return Display.INVALID_DISPLAY_GROUP;
+    }
+
+    public DisplayGroup getDisplayGroupLocked(int groupId) {
+        return mDisplayGroups.get(groupId);
     }
 
     public void dumpLocked(PrintWriter pw) {
@@ -203,229 +244,334 @@
     }
 
     void setDeviceStateLocked(int state) {
-        boolean folded = false;
-        for (int i = 0; i < mFoldedDeviceStates.length; i++) {
-            if (state == mFoldedDeviceStates[i]) {
-                folded = true;
-                break;
-            }
+        if (state != mDeviceState) {
+            resetLayoutLocked();
+            mDeviceState = state;
+            applyLayoutLocked();
+            updateLogicalDisplaysLocked();
         }
-        setDeviceFoldedLocked(folded);
-    }
-
-    void setDeviceFoldedLocked(boolean isFolded) {
-        mIsFolded = isFolded;
-
-        // Until we have fully functioning state mapping, use hardcoded states based on isFolded
-        final int state = mIsFolded ? DeviceStateToLayoutMap.STATE_FOLDED
-                : DeviceStateToLayoutMap.STATE_UNFOLDED;
-
-        if (DEBUG) {
-            Slog.d(TAG, "New device state: " + state);
-        }
-
-        final Layout layout = mDeviceStateToLayoutMap.get(state);
-        if (layout == null) {
-            return;
-        }
-        final Layout.Display displayLayout = layout.getById(Display.DEFAULT_DISPLAY);
-        if (displayLayout == null) {
-            return;
-        }
-        final DisplayDevice newDefaultDevice =
-                mDisplayDeviceRepo.getByAddressLocked(displayLayout.getAddress());
-        if (newDefaultDevice == null) {
-            return;
-        }
-
-        final LogicalDisplay defaultDisplay = mLogicalDisplays.get(Display.DEFAULT_DISPLAY);
-        mCurrentLayout = layout;
-
-        // If we're already set up accurately, return early
-        if (defaultDisplay.getPrimaryDisplayDeviceLocked() == newDefaultDevice) {
-            return;
-        }
-
-        // We need to swap the default display's display-device with the one that is supposed
-        // to be the default in the new layout.
-        final LogicalDisplay displayToSwap = getLocked(newDefaultDevice);
-        if (displayToSwap == null) {
-            Slog.w(TAG, "Canceling display swap - unexpected empty second display for: "
-                    + newDefaultDevice);
-            return;
-        }
-        defaultDisplay.swapDisplaysLocked(displayToSwap);
-
-        // We ensure that the non-default Display is always forced to be off. This was likely
-        // already done in a previous iteration, but we do it with each swap in case something in
-        // the underlying LogicalDisplays changed: like LogicalDisplay recreation, for example.
-        defaultDisplay.setEnabled(true);
-        displayToSwap.setEnabled(false);
-
-        // Update the world
-        updateLogicalDisplaysLocked();
     }
 
     private void handleDisplayDeviceAddedLocked(DisplayDevice device) {
         DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();
-        boolean isDefault = (deviceInfo.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0;
-        if (isDefault && mLogicalDisplays.get(Display.DEFAULT_DISPLAY) != null) {
-            Slog.w(TAG, "Ignoring attempt to add a second default display: " + deviceInfo);
-            isDefault = false;
+        // Internal Displays need to have additional initialization.
+        // TODO: b/168208162 - This initializes a default dynamic display layout for INTERNAL
+        // devices, which will eventually just be a fallback in case no static layout definitions
+        // exist or cannot be loaded.
+        if (deviceInfo.type == Display.TYPE_INTERNAL) {
+            initializeInternalDisplayDeviceLocked(device);
         }
 
-        if (!isDefault && mSingleDisplayDemoMode) {
-            Slog.i(TAG, "Not creating a logical display for a secondary display "
-                    + " because single display demo mode is enabled: " + deviceInfo);
-            return;
-        }
+        // Create a logical display for the new display device
+        LogicalDisplay display = createNewLogicalDisplayLocked(
+                device, Layout.assignDisplayIdLocked(false /*isDefault*/));
 
-        final int displayId = Layout.assignDisplayIdLocked(isDefault);
-        final int layerStack = assignLayerStackLocked(displayId);
-
-        final DisplayGroup displayGroup;
-        final boolean addNewDisplayGroup =
-                isDefault || (deviceInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0;
-        if (addNewDisplayGroup) {
-            final int groupId = assignDisplayGroupIdLocked(isDefault);
-            displayGroup = new DisplayGroup(groupId);
-        } else {
-            displayGroup = mDisplayIdToGroupMap.get(Display.DEFAULT_DISPLAY);
-        }
-
-        LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
-        display.updateDisplayGroupIdLocked(displayGroup.getGroupId());
-        display.updateLocked(mDisplayDeviceRepo);
-        if (!display.isValidLocked()) {
-            // This should never happen currently.
-            Slog.w(TAG, "Ignoring display device because the logical display "
-                    + "created from it was not considered valid: " + deviceInfo);
-            return;
-        }
-
-        // For foldable devices, we start the internal non-default displays as disabled.
-        // TODO - b/168208162 - this will be removed when we recalculate the layout with each
-        // display-device addition.
-        if (mFoldedDeviceStates.length > 0 && deviceInfo.type == Display.TYPE_INTERNAL
-                && !isDefault) {
-            display.setEnabled(false);
-        }
-
-        mLogicalDisplays.put(displayId, display);
-        displayGroup.addDisplayLocked(display);
-        mDisplayIdToGroupMap.append(displayId, displayGroup);
-
-        if (addNewDisplayGroup) {
-            // Group added events happen before Logical Display added events.
-            mListener.onDisplayGroupEventLocked(displayGroup.getGroupId(),
-                    LogicalDisplayMapper.DISPLAY_GROUP_EVENT_ADDED);
-        }
-
-        mListener.onLogicalDisplayEventLocked(display,
-                LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_ADDED);
-
-        if (!addNewDisplayGroup) {
-            // Group changed events happen after Logical Display added events.
-            mListener.onDisplayGroupEventLocked(displayGroup.getGroupId(),
-                    LogicalDisplayMapper.DISPLAY_GROUP_EVENT_CHANGED);
-        }
-
-        if (DEBUG) {
-            Slog.d(TAG, "New Display added: " + display);
-        }
+        applyLayoutLocked();
+        updateLogicalDisplaysLocked();
     }
 
     /**
-     * Updates all existing logical displays given the current set of display devices.
-     * Removes invalid logical displays. Sends notifications if needed.
+     * Updates the rest of the display system once all the changes are applied for display
+     * devices and logical displays. The includes releasing invalid/empty LogicalDisplays,
+     * creating/adjusting/removing DisplayGroups, and notifying the rest of the system of the
+     * relevant changes.
      */
     private void updateLogicalDisplaysLocked() {
+        // Go through all the displays and figure out if they need to be updated.
+        // Loops in reverse so that displays can be removed during the loop without affecting the
+        // rest of the loop.
         for (int i = mLogicalDisplays.size() - 1; i >= 0; i--) {
             final int displayId = mLogicalDisplays.keyAt(i);
             LogicalDisplay display = mLogicalDisplays.valueAt(i);
 
             mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked());
             display.getNonOverrideDisplayInfoLocked(mTempNonOverrideDisplayInfo);
-            DisplayEventReceiver.FrameRateOverride[] frameRatesOverrides =
-                    display.getFrameRateOverrides();
+
             display.updateLocked(mDisplayDeviceRepo);
-            final DisplayGroup changedDisplayGroup;
+            final DisplayInfo newDisplayInfo = display.getDisplayInfoLocked();
+            final boolean wasPreviouslyUpdated = mUpdatedLogicalDisplays.get(displayId);
+
+            // The display is no longer valid and needs to be removed.
             if (!display.isValidLocked()) {
-                mLogicalDisplays.removeAt(i);
-                final DisplayGroup displayGroup = mDisplayIdToGroupMap.removeReturnOld(displayId);
-                displayGroup.removeDisplayLocked(display);
+                mUpdatedLogicalDisplays.delete(displayId);
 
-                mListener.onLogicalDisplayEventLocked(display,
-                        LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REMOVED);
-
-                changedDisplayGroup = displayGroup;
-            } else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) {
-                final int flags = display.getDisplayInfoLocked().flags;
-                final DisplayGroup defaultDisplayGroup = mDisplayIdToGroupMap.get(
-                        Display.DEFAULT_DISPLAY);
-                if ((flags & Display.FLAG_OWN_DISPLAY_GROUP) != 0) {
-                    // The display should have its own DisplayGroup.
-                    if (defaultDisplayGroup.removeDisplayLocked(display)) {
-                        final int groupId = assignDisplayGroupIdLocked(false);
-                        final DisplayGroup displayGroup = new DisplayGroup(groupId);
-                        displayGroup.addDisplayLocked(display);
-                        display.updateDisplayGroupIdLocked(groupId);
-                        mDisplayIdToGroupMap.append(display.getDisplayIdLocked(), displayGroup);
-                        mListener.onDisplayGroupEventLocked(displayGroup.getGroupId(),
-                                LogicalDisplayMapper.DISPLAY_GROUP_EVENT_ADDED);
-                        changedDisplayGroup = defaultDisplayGroup;
-                    } else {
-                        changedDisplayGroup = null;
-                    }
-                } else {
-                    // The display should be a part of the default DisplayGroup.
-                    final DisplayGroup displayGroup = mDisplayIdToGroupMap.get(displayId);
-                    if (displayGroup != defaultDisplayGroup) {
-                        displayGroup.removeDisplayLocked(display);
-                        defaultDisplayGroup.addDisplayLocked(display);
-                        display.updateDisplayGroupIdLocked(defaultDisplayGroup.getGroupId());
-                        mListener.onDisplayGroupEventLocked(defaultDisplayGroup.getGroupId(),
-                                LogicalDisplayMapper.DISPLAY_GROUP_EVENT_CHANGED);
-                        mDisplayIdToGroupMap.put(displayId, defaultDisplayGroup);
-                        changedDisplayGroup = displayGroup;
-                    } else {
-                        changedDisplayGroup = null;
-                    }
+                // Remove from group
+                final DisplayGroup displayGroup = getDisplayGroupLocked(
+                        getDisplayGroupIdFromDisplayIdLocked(displayId));
+                if (displayGroup != null) {
+                    displayGroup.removeDisplayLocked(display);
                 }
 
-                final String oldUniqueId = mTempDisplayInfo.uniqueId;
-                final String newUniqueId = display.getDisplayInfoLocked().uniqueId;
-                final int eventMsg = TextUtils.equals(oldUniqueId, newUniqueId)
-                        ? LOGICAL_DISPLAY_EVENT_CHANGED : LOGICAL_DISPLAY_EVENT_SWAPPED;
-                mListener.onLogicalDisplayEventLocked(display, eventMsg);
+                if (wasPreviouslyUpdated) {
+                    // The display isn't actually removed from our internal data structures until
+                    // after the notification is sent; see {@link #sendUpdatesForDisplaysLocked}.
+                    Slog.i(TAG, "Removing display: " + displayId);
+                    mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_REMOVED);
+                } else {
+                    // This display never left this class, safe to remove without notification
+                    mLogicalDisplays.removeAt(i);
+                }
+                continue;
+
+            // The display is new.
+            } else if (!wasPreviouslyUpdated) {
+                Slog.i(TAG, "Adding new display: " + displayId + ": " + newDisplayInfo);
+                assignDisplayGroupLocked(display);
+                mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_ADDED);
+
+            // Underlying displays device has changed to a different one.
+            } else if (!TextUtils.equals(mTempDisplayInfo.uniqueId, newDisplayInfo.uniqueId)) {
+                // FLAG_OWN_DISPLAY_GROUP could have changed, recalculate just in case
+                assignDisplayGroupLocked(display);
+                mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_SWAPPED);
+
+            // Something about the display device has changed.
+            } else if (!mTempDisplayInfo.equals(newDisplayInfo)) {
+                // FLAG_OWN_DISPLAY_GROUP could have changed, recalculate just in case
+                assignDisplayGroupLocked(display);
+                mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_CHANGED);
+
+            // Display frame rate overrides changed.
             } else if (!display.getPendingFrameRateOverrideUids().isEmpty()) {
-                mListener.onLogicalDisplayEventLocked(display,
-                        LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED);
-                changedDisplayGroup = null;
+                mLogicalDisplaysToUpdate.put(
+                        displayId, LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED);
+
+            // Non-override display values changed.
             } else {
-                // While applications shouldn't know nor care about the non-overridden info, we
+                // While application shouldn't know nor care about the non-overridden info, we
                 // still need to let WindowManager know so it can update its own internal state for
                 // things like display cutouts.
                 display.getNonOverrideDisplayInfoLocked(mTempDisplayInfo);
                 if (!mTempNonOverrideDisplayInfo.equals(mTempDisplayInfo)) {
-                    mListener.onLogicalDisplayEventLocked(display,
-                            LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_CHANGED);
+                    mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_CHANGED);
                 }
-                changedDisplayGroup = null;
             }
 
-            // CHANGED and REMOVED DisplayGroup events should always fire after Display events.
-            if (changedDisplayGroup != null) {
-                final int event = changedDisplayGroup.isEmptyLocked()
-                        ? LogicalDisplayMapper.DISPLAY_GROUP_EVENT_REMOVED
-                        : LogicalDisplayMapper.DISPLAY_GROUP_EVENT_CHANGED;
-                mListener.onDisplayGroupEventLocked(changedDisplayGroup.getGroupId(), event);
+            mUpdatedLogicalDisplays.put(displayId, true);
+        }
+
+        // Go through the groups and do the same thing. We do this after displays since group
+        // information can change in the previous loop.
+        // Loops in reverse so that groups can be removed during the loop without affecting the
+        // rest of the loop.
+        for (int i = mDisplayGroups.size() - 1; i >= 0; i--) {
+            final int groupId = mDisplayGroups.keyAt(i);
+            final DisplayGroup group = mDisplayGroups.valueAt(i);
+            final boolean wasPreviouslyUpdated = mUpdatedDisplayGroups.indexOfKey(groupId) < 0;
+            final int changeCount = group.getChangeCountLocked();
+
+            if (group.isEmptyLocked()) {
+                mUpdatedDisplayGroups.delete(groupId);
+                if (wasPreviouslyUpdated) {
+                    mDisplayGroupsToUpdate.put(groupId, DISPLAY_GROUP_EVENT_REMOVED);
+                }
+                continue;
+            } else if (!wasPreviouslyUpdated) {
+                mDisplayGroupsToUpdate.put(groupId, DISPLAY_GROUP_EVENT_ADDED);
+            } else if (mUpdatedDisplayGroups.get(groupId) != changeCount) {
+                mDisplayGroupsToUpdate.put(groupId, DISPLAY_GROUP_EVENT_CHANGED);
+            }
+            mUpdatedDisplayGroups.put(groupId, changeCount);
+        }
+
+        // Send the display and display group updates in order by message type. This is important
+        // to ensure that addition and removal notifications happen in the right order.
+        sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_ADDED);
+        sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_REMOVED);
+        sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_CHANGED);
+        sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED);
+        sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_ADDED);
+        sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_SWAPPED);
+        sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_CHANGED);
+        sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_REMOVED);
+
+        mLogicalDisplaysToUpdate.clear();
+        mDisplayGroupsToUpdate.clear();
+    }
+
+    /**
+     * Send the specified message for all relevant displays in the specified display-to-message map.
+     */
+    private void sendUpdatesForDisplaysLocked(int msg) {
+        for (int i = mLogicalDisplaysToUpdate.size() - 1; i >= 0; --i) {
+            final int currMsg = mLogicalDisplaysToUpdate.valueAt(i);
+            if (currMsg != msg) {
+                continue;
+            }
+
+            final int id = mLogicalDisplaysToUpdate.keyAt(i);
+            mListener.onLogicalDisplayEventLocked(getDisplayLocked(id), msg);
+            if (msg == LOGICAL_DISPLAY_EVENT_REMOVED) {
+                // We wait until we sent the EVENT_REMOVED event before actually removing the
+                // display.
+                mLogicalDisplays.delete(id);
             }
         }
     }
 
-    private int assignDisplayGroupIdLocked(boolean isDefault) {
-        return isDefault ? Display.DEFAULT_DISPLAY_GROUP : mNextNonDefaultGroupId++;
+    /**
+     * Send the specified message for all relevant display groups in the specified message map.
+     */
+    private void sendUpdatesForGroupsLocked(int msg) {
+        for (int i = mDisplayGroupsToUpdate.size() - 1; i >= 0; --i) {
+            final int currMsg = mDisplayGroupsToUpdate.valueAt(i);
+            if (currMsg != msg) {
+                continue;
+            }
+
+            final int id = mDisplayGroupsToUpdate.keyAt(i);
+            mListener.onDisplayGroupEventLocked(id, msg);
+            if (msg == DISPLAY_GROUP_EVENT_REMOVED) {
+                // We wait until we sent the EVENT_REMOVED event before actually removing the
+                // group.
+                mDisplayGroups.delete(id);
+            }
+        }
+    }
+
+    private void assignDisplayGroupLocked(LogicalDisplay display) {
+        final int displayId = display.getDisplayIdLocked();
+
+        // Get current display group data
+        int groupId = getDisplayGroupIdFromDisplayIdLocked(displayId);
+        final DisplayGroup oldGroup = getDisplayGroupLocked(groupId);
+
+        // Get the new display group if a change is needed
+        final DisplayInfo info = display.getDisplayInfoLocked();
+        final boolean needsOwnDisplayGroup = (info.flags & Display.FLAG_OWN_DISPLAY_GROUP) != 0;
+        final boolean hasOwnDisplayGroup = groupId != Display.DEFAULT_DISPLAY_GROUP;
+        if (groupId == Display.INVALID_DISPLAY_GROUP
+                || hasOwnDisplayGroup != needsOwnDisplayGroup) {
+            groupId = assignDisplayGroupIdLocked(needsOwnDisplayGroup);
+        }
+
+        // Create a new group if needed
+        DisplayGroup newGroup = getDisplayGroupLocked(groupId);
+        if (newGroup == null) {
+            newGroup = new DisplayGroup(groupId);
+            mDisplayGroups.append(groupId, newGroup);
+        }
+        if (oldGroup != newGroup) {
+            if (oldGroup != null) {
+                oldGroup.removeDisplayLocked(display);
+            }
+            newGroup.addDisplayLocked(display);
+            display.updateDisplayGroupIdLocked(groupId);
+            Slog.i(TAG, "Setting new display group " + groupId + " for display "
+                    + displayId + ", from previous group: "
+                    + (oldGroup != null ? oldGroup.getGroupId() : "null"));
+        }
+    }
+
+    /**
+     * Resets the current layout in preparation for a new layout. Layouts can specify if some
+     * displays should be disabled (OFF). When switching from one layout to another, we go
+     * through each of the displays and make sure any displays we might have disabled are
+     * enabled again.
+     */
+    private void resetLayoutLocked() {
+        final Layout layout = mDeviceStateToLayoutMap.get(mDeviceState);
+        for (int i = layout.size() - 1; i >= 0; i--) {
+            final Layout.Display displayLayout = layout.getAt(i);
+            final LogicalDisplay display = getDisplayLocked(displayLayout.getLogicalDisplayId());
+            if (display != null) {
+                enableDisplayLocked(display, true); // Reset all displays back to enabled
+            }
+        }
+    }
+
+
+    /**
+     * Apply (or reapply) the currently selected display layout.
+     */
+    private void applyLayoutLocked() {
+        final Layout layout = mDeviceStateToLayoutMap.get(mDeviceState);
+        mCurrentLayout = layout;
+        Slog.i(TAG, "Applying the display layout for device state(" + mDeviceState
+                + "): " + layout);
+
+        // Go through each of the displays in the current layout set.
+        final int size = layout.size();
+        for (int i = 0; i < size; i++) {
+            final Layout.Display displayLayout = layout.getAt(i);
+
+            // If the underlying display-device we want to use for this display
+            // doesn't exist, then skip it. This can happen at startup as display-devices
+            // trickle in one at a time. When the new display finally shows up, the layout is
+            // recalculated so that the display is properly added to the current layout.
+            final DisplayAddress address = displayLayout.getAddress();
+            final DisplayDevice device = mDisplayDeviceRepo.getByAddressLocked(address);
+            if (device == null) {
+                Slog.w(TAG, "The display device (" + address + "), is not available"
+                        + " for the display state " + mDeviceState);
+                continue;
+            }
+
+            // Now that we have a display-device, we need a LogicalDisplay to map it to. Find the
+            // right one, if it doesn't exist, create a new one.
+            final int logicalDisplayId = displayLayout.getLogicalDisplayId();
+            LogicalDisplay newDisplay = getDisplayLocked(logicalDisplayId);
+            if (newDisplay == null) {
+                newDisplay = createNewLogicalDisplayLocked(
+                        null /*displayDevice*/, logicalDisplayId);
+            }
+
+            // Now swap the underlying display devices between the old display and the new display
+            final LogicalDisplay oldDisplay = getDisplayLocked(device);
+            if (newDisplay != oldDisplay) {
+                newDisplay.swapDisplaysLocked(oldDisplay);
+            }
+            enableDisplayLocked(newDisplay, displayLayout.isEnabled());
+        }
+    }
+
+
+    /**
+     * Creates a new logical display for the specified device and display Id and adds it to the list
+     * of logical displays.
+     *
+     * @param device The device to associate with the LogicalDisplay.
+     * @param displayId The display ID to give the new display. If invalid, a new ID is assigned.
+     * @param isDefault Indicates if we are creating the default display.
+     * @return The new logical display if created, null otherwise.
+     */
+    private LogicalDisplay createNewLogicalDisplayLocked(DisplayDevice device, int displayId) {
+        final int layerStack = assignLayerStackLocked(displayId);
+        final LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
+        display.updateLocked(mDisplayDeviceRepo);
+        mLogicalDisplays.put(displayId, display);
+        enableDisplayLocked(display, device != null);
+        return display;
+    }
+
+    private void enableDisplayLocked(LogicalDisplay display, boolean isEnabled) {
+        final int displayId = display.getDisplayIdLocked();
+        final DisplayInfo info = display.getDisplayInfoLocked();
+
+        final boolean disallowSecondaryDisplay = mSingleDisplayDemoMode
+                && (info.type != Display.TYPE_INTERNAL);
+        if (isEnabled && disallowSecondaryDisplay) {
+            Slog.i(TAG, "Not creating a logical display for a secondary display because single"
+                    + " display demo mode is enabled: " + display.getDisplayInfoLocked());
+            isEnabled = false;
+        }
+
+        display.setEnabled(isEnabled);
+    }
+
+    private int assignDisplayGroupIdLocked(boolean isOwnDisplayGroup) {
+        return isOwnDisplayGroup ? mNextNonDefaultGroupId++ : Display.DEFAULT_DISPLAY_GROUP;
+    }
+
+    private void initializeInternalDisplayDeviceLocked(DisplayDevice device) {
+        // We always want to make sure that our default display layout creates a logical
+        // display for every internal display device that is found.
+        // To that end, when we are notified of a new internal display, we add it to
+        // the default definition if it is not already there.
+        final Layout layoutSet = mDeviceStateToLayoutMap.get(DeviceStateToLayoutMap.STATE_DEFAULT);
+        final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
+        final boolean isDefault = (info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0;
+        layoutSet.createDisplayLocked(info.address, isDefault, true /* isEnabled */);
     }
 
     private int assignLayerStackLocked(int displayId) {
diff --git a/services/core/java/com/android/server/display/layout/Layout.java b/services/core/java/com/android/server/display/layout/Layout.java
index 18f39e6..ef33667 100644
--- a/services/core/java/com/android/server/display/layout/Layout.java
+++ b/services/core/java/com/android/server/display/layout/Layout.java
@@ -57,7 +57,7 @@
      * @return The new layout.
      */
     public Display createDisplayLocked(
-            @NonNull DisplayAddress address, boolean isDefault) {
+            @NonNull DisplayAddress address, boolean isDefault, boolean isEnabled) {
         if (contains(address)) {
             Slog.w(TAG, "Attempting to add second definition for display-device: " + address);
             return null;
@@ -74,7 +74,7 @@
         // different layouts, a logical display can be destroyed and later recreated with the
         // same logical display ID.
         final int logicalDisplayId = assignDisplayIdLocked(isDefault);
-        final Display layout = new Display(address, logicalDisplayId);
+        final Display layout = new Display(address, logicalDisplayId, isEnabled);
 
         mDisplays.add(layout);
         return layout;
@@ -130,17 +130,25 @@
      * Describes how a {@link LogicalDisplay} is built from {@link DisplayDevice}s.
      */
     public static class Display {
+        // Address of the display device to map to this display.
         private final DisplayAddress mAddress;
+
+        // Logical Display ID to apply to this display.
         private final int mLogicalDisplayId;
 
-        Display(@NonNull DisplayAddress address, int logicalDisplayId) {
+        // Indicates that this display is not usable and should remain off.
+        private final boolean mIsEnabled;
+
+        Display(@NonNull DisplayAddress address, int logicalDisplayId, boolean isEnabled) {
             mAddress = address;
             mLogicalDisplayId = logicalDisplayId;
+            mIsEnabled = isEnabled;
         }
 
         @Override
         public String toString() {
-            return "{addr: " + mAddress + ", dispId: " + mLogicalDisplayId + "}";
+            return "{addr: " + mAddress + ", dispId: " + mLogicalDisplayId
+                    + "(" + (mIsEnabled ? "ON" : "OFF") + ")}";
         }
 
         public DisplayAddress getAddress() {
@@ -150,5 +158,9 @@
         public int getLogicalDisplayId() {
             return mLogicalDisplayId;
         }
+
+        public boolean isEnabled() {
+            return mIsEnabled;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/graphics/fonts/FontCrashDetector.java b/services/core/java/com/android/server/graphics/fonts/FontCrashDetector.java
deleted file mode 100644
index b082b25..0000000
--- a/services/core/java/com/android/server/graphics/fonts/FontCrashDetector.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.graphics.fonts;
-
-import android.annotation.NonNull;
-import android.util.Slog;
-
-import java.io.File;
-import java.io.IOException;
-
-/**
- * A class to detect font-related native crash.
- *
- * <p>If a fs-verity protected file is accessed through mmap and corrupted file block is detected,
- * SIGBUG signal is generated and the process will crash. To find corrupted files and remove them,
- * we use a marker file to detect crash.
- * <ol>
- *     <li>Create a marker file before reading fs-verity protected font files.
- *     <li>Delete the marker file after reading font files successfully.
- *     <li>If the marker file is found in the next process startup, it means that the process
- *         crashed before. We will delete font files to prevent crash loop.
- * </ol>
- *
- * <p>Example usage:
- * <pre>
- *     FontCrashDetector detector = new FontCrashDetector(new File("/path/to/marker_file"));
- *     if (detector.hasCrashed()) {
- *         // Do cleanup
- *     }
- *     try (FontCrashDetector.MonitoredBlock b = detector.start()) {
- *         // Read files
- *     }
- * </pre>
- *
- * <p>This class DOES NOT detect Java exceptions. If a Java exception is thrown while monitoring
- * crash, the marker file will be deleted. Creating and deleting marker files are not lightweight.
- * Please use this class sparingly with caution.
- */
-/* package */ final class FontCrashDetector {
-
-    private static final String TAG = "FontCrashDetector";
-
-    @NonNull
-    private final File mMarkerFile;
-
-    /* package */ FontCrashDetector(@NonNull File markerFile) {
-        mMarkerFile = markerFile;
-    }
-
-    /* package */ boolean hasCrashed() {
-        return mMarkerFile.exists();
-    }
-
-    /* package */ void clear() {
-        if (!mMarkerFile.delete()) {
-            Slog.e(TAG, "Could not delete marker file: " + mMarkerFile);
-        }
-    }
-
-    /** Starts crash monitoring. */
-    /* package */ MonitoredBlock start() {
-        try {
-            mMarkerFile.createNewFile();
-        } catch (IOException e) {
-            Slog.e(TAG, "Could not create marker file: " + mMarkerFile, e);
-        }
-        return new MonitoredBlock();
-    }
-
-    /** A helper class to monitor crash with try-with-resources syntax. */
-    /* package */ class MonitoredBlock implements AutoCloseable {
-        /** Ends crash monitoring. */
-        @Override
-        public void close() {
-            clear();
-        }
-    }
-}
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 01e839d..900ec90 100644
--- a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
@@ -63,7 +63,6 @@
     private static final String TAG = "FontManagerService";
 
     private static final String FONT_FILES_DIR = "/data/fonts/files";
-    private static final String CRASH_MARKER_FILE = "/data/fonts/config/crash.txt";
 
     @Override
     public FontConfig getFontConfig() {
@@ -200,10 +199,6 @@
     private final Object mUpdatableFontDirLock = new Object();
 
     @GuardedBy("mUpdatableFontDirLock")
-    @NonNull
-    private final FontCrashDetector mFontCrashDetector;
-
-    @GuardedBy("mUpdatableFontDirLock")
     @Nullable
     private final UpdatableFontDir mUpdatableFontDir;
 
@@ -217,7 +212,6 @@
 
     private FontManagerService(Context context) {
         mContext = context;
-        mFontCrashDetector = new FontCrashDetector(new File(CRASH_MARKER_FILE));
         mUpdatableFontDir = createUpdatableFontDir();
         initialize();
     }
@@ -244,19 +238,8 @@
                 }
                 return;
             }
-            if (mFontCrashDetector.hasCrashed()) {
-                Slog.i(TAG, "Crash detected. Clearing font updates.");
-                try {
-                    mUpdatableFontDir.clearUpdates();
-                } catch (SystemFontException e) {
-                    Slog.e(TAG, "Failed to clear updates.", e);
-                }
-                mFontCrashDetector.clear();
-            }
-            try (FontCrashDetector.MonitoredBlock ignored = mFontCrashDetector.start()) {
-                mUpdatableFontDir.loadFontFileMap();
-                updateSerializedFontMap();
-            }
+            mUpdatableFontDir.loadFontFileMap();
+            updateSerializedFontMap();
         }
     }
 
@@ -286,10 +269,8 @@
                         FontManager.RESULT_ERROR_VERSION_MISMATCH,
                         "The base config version is older than current.");
             }
-            try (FontCrashDetector.MonitoredBlock ignored = mFontCrashDetector.start()) {
-                mUpdatableFontDir.update(requests);
-                updateSerializedFontMap();
-            }
+            mUpdatableFontDir.update(requests);
+            updateSerializedFontMap();
         }
     }
 
@@ -300,10 +281,8 @@
                     "The font updater is disabled.");
         }
         synchronized (mUpdatableFontDirLock) {
-            try (FontCrashDetector.MonitoredBlock ignored = mFontCrashDetector.start()) {
-                mUpdatableFontDir.clearUpdates();
-                updateSerializedFontMap();
-            }
+            mUpdatableFontDir.clearUpdates();
+            updateSerializedFontMap();
         }
     }
 
diff --git a/services/core/java/com/android/server/graphics/fonts/PersistentSystemFontConfig.java b/services/core/java/com/android/server/graphics/fonts/PersistentSystemFontConfig.java
index d514aab..62337c7 100644
--- a/services/core/java/com/android/server/graphics/fonts/PersistentSystemFontConfig.java
+++ b/services/core/java/com/android/server/graphics/fonts/PersistentSystemFontConfig.java
@@ -46,7 +46,7 @@
     private static final String ATTR_VALUE = "value";
 
     /* package */ static class Config {
-        public long lastModifiedDate;
+        public long lastModifiedMillis;
         public final Set<String> updatedFontDirs = new ArraySet<>();
         public final List<FontConfig.FontFamily> fontFamilies = new ArrayList<>();
     }
@@ -73,7 +73,7 @@
             } else if (depth == 2) {
                 switch (tag) {
                     case TAG_LAST_MODIFIED_DATE:
-                        out.lastModifiedDate = parseLongAttribute(parser, ATTR_VALUE, 0);
+                        out.lastModifiedMillis = parseLongAttribute(parser, ATTR_VALUE, 0);
                         break;
                     case TAG_UPDATED_FONT_DIR:
                         out.updatedFontDirs.add(getAttribute(parser, ATTR_VALUE));
@@ -101,7 +101,7 @@
 
         out.startTag(null, TAG_ROOT);
         out.startTag(null, TAG_LAST_MODIFIED_DATE);
-        out.attribute(null, ATTR_VALUE, Long.toString(config.lastModifiedDate));
+        out.attribute(null, ATTR_VALUE, Long.toString(config.lastModifiedMillis));
         out.endTag(null, TAG_LAST_MODIFIED_DATE);
         for (String dir : config.updatedFontDirs) {
             out.startTag(null, TAG_UPDATED_FONT_DIR);
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 08ddc6d..86dbe86 100644
--- a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
+++ b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
@@ -112,7 +112,7 @@
     private final File mConfigFile;
     private final File mTmpConfigFile;
 
-    private long mLastModifiedDate;
+    private long mLastModifiedMillis;
     private int mConfigVersion = 1;
 
     /**
@@ -147,7 +147,7 @@
     /* package */ void loadFontFileMap() {
         mFontFileInfoMap.clear();
         mFontFamilyMap.clear();
-        mLastModifiedDate = 0;
+        mLastModifiedMillis = 0;
         boolean success = false;
         try {
             PersistentSystemFontConfig.Config config = new PersistentSystemFontConfig.Config();
@@ -157,7 +157,7 @@
                 Slog.e(TAG, "Failed to load config xml file", e);
                 return;
             }
-            mLastModifiedDate = config.lastModifiedDate;
+            mLastModifiedMillis = config.lastModifiedMillis;
 
             File[] dirs = mFilesDir.listFiles();
             if (dirs == null) return;
@@ -200,7 +200,7 @@
             if (!success) {
                 mFontFileInfoMap.clear();
                 mFontFamilyMap.clear();
-                mLastModifiedDate = 0;
+                mLastModifiedMillis = 0;
                 FileUtils.deleteContents(mFilesDir);
             }
         }
@@ -211,7 +211,7 @@
         FileUtils.deleteContents(mFilesDir);
         mFontFamilyMap.clear();
 
-        mLastModifiedDate = Instant.now().getEpochSecond();
+        mLastModifiedMillis = System.currentTimeMillis();
         try (FileOutputStream fos = new FileOutputStream(mConfigFile)) {
             PersistentSystemFontConfig.writeToXml(fos, createPersistentConfig());
         } catch (Exception e) {
@@ -231,7 +231,7 @@
         // Backup the mapping for rollback.
         ArrayMap<String, FontFileInfo> backupMap = new ArrayMap<>(mFontFileInfoMap);
         ArrayMap<String, FontConfig.FontFamily> backupFamilies = new ArrayMap<>(mFontFamilyMap);
-        long backupLastModifiedDate = mLastModifiedDate;
+        long backupLastModifiedDate = mLastModifiedMillis;
         boolean success = false;
         try {
             for (FontUpdateRequest request : requests) {
@@ -247,7 +247,7 @@
             }
 
             // Write config file.
-            mLastModifiedDate = Instant.now().getEpochSecond();
+            mLastModifiedMillis = Instant.now().getEpochSecond();
             try (FileOutputStream fos = new FileOutputStream(mTmpConfigFile)) {
                 PersistentSystemFontConfig.writeToXml(fos, createPersistentConfig());
             } catch (Exception e) {
@@ -269,7 +269,7 @@
                 mFontFileInfoMap.putAll(backupMap);
                 mFontFamilyMap.clear();
                 mFontFamilyMap.putAll(backupFamilies);
-                mLastModifiedDate = backupLastModifiedDate;
+                mLastModifiedMillis = backupLastModifiedDate;
             }
         }
     }
@@ -527,7 +527,7 @@
 
     private PersistentSystemFontConfig.Config createPersistentConfig() {
         PersistentSystemFontConfig.Config config = new PersistentSystemFontConfig.Config();
-        config.lastModifiedDate = mLastModifiedDate;
+        config.lastModifiedMillis = mLastModifiedMillis;
         for (FontFileInfo info : mFontFileInfoMap.values()) {
             config.updatedFontDirs.add(info.getRandomizedFontDir().getName());
         }
@@ -560,7 +560,7 @@
         // which will be used as a fallback font without being overridden.
         mergedFamilies.addAll(mFontFamilyMap.values());
         return new FontConfig(
-                mergedFamilies, config.getAliases(), mLastModifiedDate, mConfigVersion);
+                mergedFamilies, config.getAliases(), mLastModifiedMillis, mConfigVersion);
     }
 
     /* package */ int getConfigVersion() {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index b4d9b01..115cafed 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -221,7 +221,7 @@
     private int mHdmiCecVolumeControl;
 
     // Make sure HdmiCecConfig is instantiated and the XMLs are read.
-    private final HdmiCecConfig mHdmiCecConfig;
+    private HdmiCecConfig mHdmiCecConfig;
 
     /**
      * Interface to report send result.
@@ -580,6 +580,11 @@
         mHdmiCecNetwork = hdmiCecNetwork;
     }
 
+    @VisibleForTesting
+    void setHdmiCecConfig(HdmiCecConfig hdmiCecConfig) {
+        mHdmiCecConfig = hdmiCecConfig;
+    }
+
     public HdmiCecNetwork getHdmiCecNetwork() {
         return mHdmiCecNetwork;
     }
diff --git a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
index a7f34ed..4c4c978 100644
--- a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
+++ b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
@@ -259,7 +259,7 @@
     }
 
     private void mayDisableSystemAudioAndARC(int address) {
-        if (HdmiUtils.isEligibleAddressForDevice(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM, address)) {
+        if (!HdmiUtils.isEligibleAddressForDevice(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM, address)) {
             return;
         }
 
diff --git a/services/core/java/com/android/server/hdmi/cec_key_handling.md b/services/core/java/com/android/server/hdmi/cec_key_handling.md
index 1b41a67..69877be 100644
--- a/services/core/java/com/android/server/hdmi/cec_key_handling.md
+++ b/services/core/java/com/android/server/hdmi/cec_key_handling.md
@@ -1,36 +1,37 @@
 # CEC Key Handling
 
-The mapping of CEC key codes to Android key codes are at
-[HdmiCecKeycode](HdmiCecKeycode.java)
+The mapping of CEC keycodes to Android keycodes is done at [HdmiCecKeycode](HdmiCecKeycode.java).
 
 # Android TV
 
-Android TV requires special handling of some keys.
+Android TV (ATV) requires special handling of some keys.
 
-The general action for key handling is described in the table
+The general action for key handling is described in the table below.
 
 | Android Key | TV Panel                                               | OTT                        | Soundbar                                               |
 | ----------- | -----------------                                      | -------------------        | -------------------                                    |
-| general     | Send to active source                                  | handle on device           | handle on device                                       |
 | POWER       | Toggle the device power state  | Toggle the OTT power state, TV power state follows | Toggle the soundbar power state, TV power state follows|
 | TV_POWER    | Toggle the device power state  | Toggle the TV power state, OTT power state follows | Toggle the TV power state, soundbar power state follows|
 | HOME        | Turn on TV, Set active Source to TV, go to home screen | OTP, and go to home screen | OTP, and go to home screen                             |
-| volume keys | Handle on device or send to soundbar                   | Send to TV or soundbar     | Handle on device or send to TV                         |
+| Volume keys | Handle on device or send to soundbar                   | Send to TV or soundbar     | Handle on device or send to TV                         |
+| Other keys  | Forward to active source                               | Handle on device           | Handle on device                                       |
 
-Special cases and flags for each key are described below
+Special cases and flags per key are described below.
 
-## POWER
+## TV_POWER
 
 ### TV Panel
 
-TODO
+For ATV TV panel devices, TV_POWER is an alias of POWER.
 
-### OTT
+### Source Devices (OTT and Soundbar)
 
-TODO
+For ATV source devices with POWER_CONTROL_MODE set to none or CEC control disabled, TV_POWER is an alias of POWER.
 
-### Soundbar
+For all other source devices, TV_POWER toggles the TV power state and makes the OTT power state follow.
 
-TODO
+### Other Devices
+
+For any device that is not connected to a TV via HDMI and not an ATV device, TV_POWER is ignored.
 
 
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index bd577f3..016c5ed 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -1052,6 +1052,9 @@
         public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) {
             if (verbose) Slog.v(mTag, "onChange(): uri=" + uri + ", userId=" + userId);
             final String property = uri.getLastPathSegment();
+            if (property == null) {
+                return;
+            }
             if (property.equals(getServiceSettingsProperty())
                     || property.equals(Settings.Secure.USER_SETUP_COMPLETE)) {
                 synchronized (mLock) {
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index bbe52bc..edb5d97 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -590,10 +590,13 @@
             for (int i = viewports.size() - 1; i >= 0; --i) {
                 final DisplayViewport v = vArray[i] = viewports.get(i).makeCopy();
                 // deviceWidth/Height are apparently in "rotated" space, so flip them if needed.
-                int dw = (v.orientation % 2) == 0 ? v.deviceWidth : v.deviceHeight;
-                int dh = (v.orientation % 2) == 0 ? v.deviceHeight : v.deviceWidth;
-                v.logicalFrame.set(0, 0, dw, dh);
-                v.physicalFrame.set(0, 0, dw, dh);
+                if (v.orientation % 2 != 0) {
+                    final int dw = v.deviceWidth;
+                    v.deviceWidth = v.deviceHeight;
+                    v.deviceHeight = dw;
+                }
+                v.logicalFrame.set(0, 0, v.deviceWidth, v.deviceHeight);
+                v.physicalFrame.set(0, 0, v.deviceWidth, v.deviceHeight);
                 v.orientation = 0;
             }
         } else {
diff --git a/services/core/java/com/android/server/input/InputShellCommand.java b/services/core/java/com/android/server/input/InputShellCommand.java
index d08980c..720be82 100644
--- a/services/core/java/com/android/server/input/InputShellCommand.java
+++ b/services/core/java/com/android/server/input/InputShellCommand.java
@@ -29,6 +29,7 @@
 import android.view.ViewConfiguration;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -199,6 +200,8 @@
                 runRoll(inputSource, displayId);
             }  else if ("motionevent".equals(arg)) {
                 runMotionEvent(inputSource, displayId);
+            } else if ("keycombination".equals(arg)) {
+                runKeyCombination(inputSource, displayId);
             } else {
                 handleDefaultCommands(arg);
             }
@@ -224,7 +227,7 @@
             out.println();
             out.println("The commands and default sources are:");
             out.println("      text <string> (Default: touchscreen)");
-            out.println("      keyevent [--longpress] <key code number or name> ..."
+            out.println("      keyevent [--longpress|--doubletap] <key code number or name> ..."
                     + " (Default: keyboard)");
             out.println("      tap <x> <y> (Default: touchscreen)");
             out.println("      swipe <x1> <y1> <x2> <y2> [duration(ms)]"
@@ -234,6 +237,8 @@
             out.println("      press (Default: trackball)");
             out.println("      roll <dx> <dy> (Default: trackball)");
             out.println("      motionevent <DOWN|UP|MOVE|CANCEL> <x> <y> (Default: touchscreen)");
+            out.println("      keycombination <key code 1> <key code 2> ..."
+                    + " (Default: keyboard)");
         }
     }
 
@@ -282,6 +287,14 @@
         final boolean longpress = "--longpress".equals(arg);
         if (longpress) {
             arg = getNextArgRequired();
+        } else {
+            final boolean doubleTap = "--doubletap".equals(arg);
+            if (doubleTap) {
+                arg = getNextArgRequired();
+                final int keycode = KeyEvent.keyCodeFromString(arg);
+                sendKeyDoubleTap(inputSource, keycode, displayId);
+                return;
+            }
         }
 
         do {
@@ -292,22 +305,32 @@
 
     private void sendKeyEvent(int inputSource, int keyCode, boolean longpress, int displayId) {
         final long now = SystemClock.uptimeMillis();
-        int repeatCount = 0;
 
-        KeyEvent event = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, repeatCount,
+        KeyEvent event = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0 /* repeatCount */,
                 0 /*metaState*/, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/,
                 inputSource);
         event.setDisplayId(displayId);
 
         injectKeyEvent(event);
         if (longpress) {
-            repeatCount++;
-            injectKeyEvent(KeyEvent.changeTimeRepeat(event, now, repeatCount,
+            // Some long press behavior would check the event time, we set a new event time here.
+            final long nextEventTime = now + ViewConfiguration.getGlobalActionKeyTimeout();
+            injectKeyEvent(KeyEvent.changeTimeRepeat(event, nextEventTime, 1 /* repeatCount */,
                     KeyEvent.FLAG_LONG_PRESS));
         }
         injectKeyEvent(KeyEvent.changeAction(event, KeyEvent.ACTION_UP));
     }
 
+    private void sendKeyDoubleTap(int inputSource, int keyCode, int displayId) {
+        sendKeyEvent(inputSource, keyCode, false, displayId);
+        try {
+            Thread.sleep(ViewConfiguration.getDoubleTapMinTime());
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+        sendKeyEvent(inputSource, keyCode, false, displayId);
+    }
+
     private void runTap(int inputSource, int displayId) {
         inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
         sendTap(inputSource, Float.parseFloat(getNextArgRequired()),
@@ -440,4 +463,59 @@
         final long now = SystemClock.uptimeMillis();
         injectMotionEvent(inputSource, action, now, now, x, y, pressure, displayId);
     }
+
+    private void runKeyCombination(int inputSource, int displayId) {
+        String arg = getNextArgRequired();
+        ArrayList<Integer> keyCodes = new ArrayList<>();
+
+        while (arg != null) {
+            final int keyCode = KeyEvent.keyCodeFromString(arg);
+            if (keyCode == KeyEvent.KEYCODE_UNKNOWN) {
+                throw new IllegalArgumentException("Unknown keycode: " + arg);
+            }
+            keyCodes.add(keyCode);
+            arg = getNextArg();
+        }
+
+        // At least 2 keys.
+        if (keyCodes.size() < 2) {
+            throw new IllegalArgumentException("keycombination requires at least 2 keycodes");
+        }
+
+        sendKeyCombination(inputSource, keyCodes, displayId);
+    }
+
+    private void injectKeyEventAsync(KeyEvent event) {
+        InputManager.getInstance().injectInputEvent(event,
+                InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+    }
+
+    private void sendKeyCombination(int inputSource, ArrayList<Integer> keyCodes, int displayId) {
+        final long now = SystemClock.uptimeMillis();
+        final int count = keyCodes.size();
+        final KeyEvent[] events = new KeyEvent[count];
+        for (int i = 0; i < count; i++) {
+            final KeyEvent event = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCodes.get(i), 0,
+                    0 /*metaState*/, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/,
+                    inputSource);
+            event.setDisplayId(displayId);
+            events[i] = event;
+        }
+
+        for (KeyEvent event: events) {
+            // Use async inject so interceptKeyBeforeQueueing or interceptKeyBeforeDispatching could
+            // handle keys.
+            injectKeyEventAsync(event);
+        }
+
+        try {
+            Thread.sleep(ViewConfiguration.getTapTimeout());
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+
+        for (KeyEvent event: events) {
+            injectKeyEventAsync(KeyEvent.changeAction(event, KeyEvent.ACTION_UP));
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 1e66589..c0d577c 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2620,9 +2620,8 @@
                 }
                 if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
                 // Dispatch display id for InputMethodService to update context display.
-                executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOOO(
-                        MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken,
-                        mMethodMap.get(mCurMethodId).getConfigChanges()));
+                executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
+                        MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken));
                 scheduleNotifyImeUidToAudioService(mCurMethodUid);
                 if (mCurClient != null) {
                     clearClientSessionLocked(mCurClient);
@@ -3537,6 +3536,20 @@
         boolean didStart = false;
 
         InputBindResult res = null;
+        // We shows the IME when the system allows the IME focused target window to restore the
+        // IME visibility (e.g. switching to the app task when last time the IME is visible).
+        if (isTextEditor && mWindowManagerInternal.shouldRestoreImeVisibility(windowToken)) {
+            if (attribute != null) {
+                res = startInputUncheckedLocked(cs, inputContext, missingMethods,
+                        attribute, startInputFlags, startInputReason);
+                showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
+                        SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY);
+            } else {
+                res = InputBindResult.NULL_EDITOR_INFO;
+            }
+            return res;
+        }
+
         switch (softInputMode & LayoutParams.SOFT_INPUT_MASK_STATE) {
             case LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
                 if (!sameWindowFocused && (!isTextEditor || !doAutoShow)) {
@@ -3647,12 +3660,9 @@
                         hideCurrentInputLocked(mCurFocusedWindow, 0, null,
                                 SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR);
                     }
-                    res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
-                            startInputFlags, startInputReason);
-                } else {
-                    res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
-                            startInputFlags, startInputReason);
                 }
+                res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
+                        startInputFlags, startInputReason);
             } else {
                 res = InputBindResult.NULL_EDITOR_INFO;
             }
@@ -4467,8 +4477,7 @@
                     }
                     final IBinder token = (IBinder) args.arg2;
                     ((IInputMethod) args.arg1).initializeInternal(token, msg.arg1,
-                            new InputMethodPrivilegedOperationsImpl(this, token),
-                            (int) args.arg3);
+                            new InputMethodPrivilegedOperationsImpl(this, token));
                 } catch (RemoteException e) {
                 }
                 args.recycle();
@@ -5414,37 +5423,38 @@
         @BinderThread
         @ShellCommandResult
         private int onCommandWithSystemIdentity(@Nullable String cmd) {
-            if ("get-last-switch-user-id".equals(cmd)) {
-                return mService.getLastSwitchUserId(this);
-            }
-
-            // For existing "adb shell ime <command>".
-            if ("ime".equals(cmd)) {
-                final String imeCommand = getNextArg();
-                if (imeCommand == null || "help".equals(imeCommand) || "-h".equals(imeCommand)) {
-                    onImeCommandHelp();
-                    return ShellCommandResult.SUCCESS;
+            switch (TextUtils.emptyIfNull(cmd)) {
+                case "get-last-switch-user-id":
+                    return mService.getLastSwitchUserId(this);
+                case "tracing":
+                    return mService.handleShellCommandTraceInputMethod(this);
+                case "ime": {  // For "adb shell ime <command>".
+                    final String imeCommand = TextUtils.emptyIfNull(getNextArg());
+                    switch (imeCommand) {
+                        case "":
+                        case "-h":
+                        case "help":
+                            return onImeCommandHelp();
+                        case "list":
+                            return mService.handleShellCommandListInputMethods(this);
+                        case "enable":
+                            return mService.handleShellCommandEnableDisableInputMethod(this, true);
+                        case "disable":
+                            return mService.handleShellCommandEnableDisableInputMethod(this, false);
+                        case "set":
+                            return mService.handleShellCommandSetInputMethod(this);
+                        case "reset":
+                            return mService.handleShellCommandResetInputMethod(this);
+                        case "tracing":  // TODO(b/180765389): Unsupport "adb shell ime tracing"
+                            return mService.handleShellCommandTraceInputMethod(this);
+                        default:
+                            getOutPrintWriter().println("Unknown command: " + imeCommand);
+                            return ShellCommandResult.FAILURE;
+                    }
                 }
-                switch (imeCommand) {
-                    case "list":
-                        return mService.handleShellCommandListInputMethods(this);
-                    case "enable":
-                        return mService.handleShellCommandEnableDisableInputMethod(this, true);
-                    case "disable":
-                        return mService.handleShellCommandEnableDisableInputMethod(this, false);
-                    case "set":
-                        return mService.handleShellCommandSetInputMethod(this);
-                    case "reset":
-                        return mService.handleShellCommandResetInputMethod(this);
-                    case "tracing":
-                        return mService.handleShellCommandTraceInputMethod(this);
-                    default:
-                        getOutPrintWriter().println("Unknown command: " + imeCommand);
-                        return ShellCommandResult.FAILURE;
-                }
+                default:
+                    return handleDefaultCommands(cmd);
             }
-
-            return handleDefaultCommands(cmd);
         }
 
         @BinderThread
@@ -5458,10 +5468,16 @@
                 pw.println("    Synonym of dumpsys.");
                 pw.println("  ime <command> [options]");
                 pw.println("    Manipulate IMEs.  Run \"ime help\" for details.");
+                pw.println("  tracing <command>");
+                pw.println("    start: Start tracing.");
+                pw.println("    stop : Stop tracing.");
+                pw.println("    help : Show help.");
             }
         }
 
-        private void onImeCommandHelp() {
+        @BinderThread
+        @ShellCommandResult
+        private int onImeCommandHelp() {
             try (IndentingPrintWriter pw =
                          new IndentingPrintWriter(getOutPrintWriter(), "  ", 100)) {
                 pw.println("ime <command>:");
@@ -5516,6 +5532,7 @@
 
                 pw.decreaseIndent();
             }
+            return ShellCommandResult.SUCCESS;
         }
     }
 
diff --git a/services/core/java/com/android/server/location/GeocoderProxy.java b/services/core/java/com/android/server/location/GeocoderProxy.java
index 3ac148d..c93c4b1 100644
--- a/services/core/java/com/android/server/location/GeocoderProxy.java
+++ b/services/core/java/com/android/server/location/GeocoderProxy.java
@@ -24,7 +24,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 
-import com.android.server.ServiceWatcher;
+import com.android.server.servicewatcher.ServiceWatcher;
 
 import java.util.Collections;
 
diff --git a/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java b/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java
index 7b400b6..e1c8700 100644
--- a/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java
+++ b/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java
@@ -17,7 +17,6 @@
 package com.android.server.location;
 
 import android.annotation.Nullable;
-import android.content.ComponentName;
 import android.content.Context;
 import android.hardware.location.ActivityRecognitionHardware;
 import android.hardware.location.IActivityRecognitionHardwareClient;
@@ -26,7 +25,8 @@
 import android.os.RemoteException;
 import android.util.Log;
 
-import com.android.server.ServiceWatcher;
+import com.android.server.servicewatcher.ServiceWatcher;
+import com.android.server.servicewatcher.ServiceWatcher.BoundService;
 
 /**
  * Proxy class to bind GmsCore to the ActivityRecognitionHardware.
@@ -82,7 +82,7 @@
         return resolves;
     }
 
-    private void onBind(IBinder binder, ComponentName service) throws RemoteException {
+    private void onBind(IBinder binder, BoundService service) throws RemoteException {
         String descriptor = binder.getInterfaceDescriptor();
 
         if (IActivityRecognitionHardwareWatcher.class.getCanonicalName().equals(descriptor)) {
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 1bf9da7..2920ddb 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -52,6 +52,7 @@
 import android.location.GnssMeasurementCorrections;
 import android.location.GnssMeasurementRequest;
 import android.location.IGeocodeListener;
+import android.location.IGnssAntennaInfoListener;
 import android.location.IGnssMeasurementsListener;
 import android.location.IGnssNavigationMessageListener;
 import android.location.IGnssNmeaListener;
@@ -63,6 +64,7 @@
 import android.location.Location;
 import android.location.LocationManager;
 import android.location.LocationManagerInternal;
+import android.location.LocationManagerInternal.OnProviderLocationTagsChangeListener;
 import android.location.LocationProvider;
 import android.location.LocationRequest;
 import android.location.LocationTime;
@@ -82,6 +84,7 @@
 import android.provider.Settings;
 import android.stats.location.LocationStatsEnums;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.IndentingPrintWriter;
 import android.util.Log;
 
@@ -252,9 +255,12 @@
 
     // @GuardedBy("mProviderManagers")
     // hold lock for writes, no lock necessary for simple reads
-    private final CopyOnWriteArrayList<LocationProviderManager> mProviderManagers =
+    final CopyOnWriteArrayList<LocationProviderManager> mProviderManagers =
             new CopyOnWriteArrayList<>();
 
+    @GuardedBy("mLock")
+    private @Nullable OnProviderLocationTagsChangeListener mOnProviderLocationTagsChangeListener;
+
     LocationManagerService(Context context, Injector injector, LocationEventLog eventLog) {
         mContext = context.createAttributionContext(ATTRIBUTION_TAG);
         mInjector = injector;
@@ -284,7 +290,7 @@
     }
 
     @Nullable
-    private LocationProviderManager getLocationProviderManager(String providerName) {
+    LocationProviderManager getLocationProviderManager(String providerName) {
         if (providerName == null) {
             return null;
         }
@@ -319,8 +325,9 @@
             Preconditions.checkState(getLocationProviderManager(manager.getName()) == null);
 
             manager.startManager();
+            manager.setOnProviderLocationTagsChangeListener(
+                    mOnProviderLocationTagsChangeListener);
             if (realProvider != null) {
-
                 // custom logic wrapping all non-passive providers
                 if (manager != mPassiveManager) {
                     boolean enableStationaryThrottling = Settings.Global.getInt(
@@ -331,7 +338,6 @@
                                 mInjector, realProvider, mEventLog);
                     }
                 }
-
                 manager.setRealProvider(realProvider);
             }
             mProviderManagers.add(manager);
@@ -456,8 +462,9 @@
                     .setPowerUsage(Integer.parseInt(fragments[8]))
                     .setAccuracy(Integer.parseInt(fragments[9]))
                     .build();
-            getOrAddLocationProviderManager(name).setMockProvider(
-                    new MockLocationProvider(properties, CallerIdentity.fromContext(mContext)));
+            final LocationProviderManager manager = getOrAddLocationProviderManager(name);
+            manager.setMockProvider(new MockLocationProvider(properties,
+                    CallerIdentity.fromContext(mContext), Collections.emptySet()));
         }
     }
 
@@ -924,6 +931,22 @@
     }
 
     @Override
+    public void addGnssAntennaInfoListener(IGnssAntennaInfoListener listener, String packageName,
+            @Nullable String attributionTag, String listenerId) {
+        if (mGnssManagerService != null) {
+            mGnssManagerService.addGnssAntennaInfoListener(listener, packageName, attributionTag,
+                    listenerId);
+        }
+    }
+
+    @Override
+    public void removeGnssAntennaInfoListener(IGnssAntennaInfoListener listener) {
+        if (mGnssManagerService != null) {
+            mGnssManagerService.removeGnssAntennaInfoListener(listener);
+        }
+    }
+
+    @Override
     public void addProviderRequestListener(IProviderRequestListener listener) {
         for (LocationProviderManager manager : mProviderManagers) {
             manager.addProviderRequestListener(listener);
@@ -1147,15 +1170,16 @@
 
     @Override
     public void addTestProvider(String provider, ProviderProperties properties,
-            String packageName, String attributionTag) {
+            List<String> extraAttributionTags, String packageName, String attributionTag) {
         // unsafe is ok because app ops will verify the package name
         CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName, attributionTag);
         if (!mInjector.getAppOpsHelper().noteOp(AppOpsManager.OP_MOCK_LOCATION, identity)) {
             return;
         }
 
-        getOrAddLocationProviderManager(provider).setMockProvider(
-                new MockLocationProvider(properties, identity));
+        final LocationProviderManager manager = getOrAddLocationProviderManager(provider);
+        manager.setMockProvider(new MockLocationProvider(properties, identity,
+                new ArraySet<>(extraAttributionTags)));
     }
 
     @Override
@@ -1288,13 +1312,13 @@
 
         ipw.println("Historical Aggregate Location Provider Data:");
         ipw.increaseIndent();
-        ArrayMap<String, ArrayMap<String, LocationEventLog.AggregateStats>> aggregateStats =
+        ArrayMap<String, ArrayMap<CallerIdentity, LocationEventLog.AggregateStats>> aggregateStats =
                 mEventLog.copyAggregateStats();
         for (int i = 0; i < aggregateStats.size(); i++) {
             ipw.print(aggregateStats.keyAt(i));
             ipw.println(":");
             ipw.increaseIndent();
-            ArrayMap<String, LocationEventLog.AggregateStats> providerStats =
+            ArrayMap<CallerIdentity, LocationEventLog.AggregateStats> providerStats =
                     aggregateStats.valueAt(i);
             for (int j = 0; j < providerStats.size(); j++) {
                 ipw.print(providerStats.keyAt(j));
@@ -1362,7 +1386,7 @@
                 if (provider != null && !provider.equals(manager.getName())) {
                     continue;
                 }
-                if (identity.equalsIgnoringListenerId(manager.getIdentity())) {
+                if (identity.equals(manager.getIdentity())) {
                     return true;
                 }
             }
@@ -1392,6 +1416,19 @@
 
             return new LocationTime(location.getTime(), location.getElapsedRealtimeNanos());
         }
+
+        @Override
+        public void setOnProviderLocationTagsChangeListener(
+                @Nullable OnProviderLocationTagsChangeListener listener) {
+            synchronized (mLock) {
+                mOnProviderLocationTagsChangeListener = listener;
+                final int providerCount = mProviderManagers.size();
+                for (int i = 0; i < providerCount; i++) {
+                    final LocationProviderManager manager = mProviderManagers.get(i);
+                    manager.setOnProviderLocationTagsChangeListener(listener);
+                }
+            }
+        }
     }
 
     private static class SystemInjector implements Injector {
diff --git a/services/core/java/com/android/server/location/LocationShellCommand.java b/services/core/java/com/android/server/location/LocationShellCommand.java
index f0dd8b5..5dc3ed8 100644
--- a/services/core/java/com/android/server/location/LocationShellCommand.java
+++ b/services/core/java/com/android/server/location/LocationShellCommand.java
@@ -26,6 +26,8 @@
 
 import java.io.PrintWriter;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -50,15 +52,11 @@
 
         switch (cmd) {
             case "is-location-enabled": {
-                int userId = parseUserId();
-                boolean enabled = mService.isLocationEnabledForUser(userId);
-                getOutPrintWriter().println(enabled);
+                handleIsLocationEnabled();
                 return 0;
             }
             case "set-location-enabled": {
-                int userId = parseUserId();
-                boolean enabled = Boolean.parseBoolean(getNextArgRequired());
-                mService.setLocationEnabledForUser(enabled, userId);
+                handleSetLocationEnabled();
                 return 0;
             }
             case "providers": {
@@ -73,36 +71,23 @@
     private int parseProvidersCommand(String cmd) {
         switch (cmd) {
             case "add-test-provider": {
-                String provider = getNextArgRequired();
-                ProviderProperties properties = parseTestProviderProviderProperties();
-                mService.addTestProvider(provider, properties, mContext.getOpPackageName(),
-                        mContext.getFeatureId());
+                handleAddTestProvider();
                 return 0;
             }
             case "remove-test-provider": {
-                String provider = getNextArgRequired();
-                mService.removeTestProvider(provider, mContext.getOpPackageName(),
-                        mContext.getFeatureId());
+                handleRemoveTestProvider();
                 return 0;
             }
             case "set-test-provider-enabled": {
-                String provider = getNextArgRequired();
-                boolean enabled = Boolean.parseBoolean(getNextArgRequired());
-                mService.setTestProviderEnabled(provider, enabled, mContext.getOpPackageName(),
-                        mContext.getFeatureId());
+                handleSetTestProviderEnabled();
                 return 0;
             }
             case "set-test-provider-location": {
-                String provider = getNextArgRequired();
-                Location location = parseTestProviderLocation(provider);
-                mService.setTestProviderLocation(provider, location, mContext.getOpPackageName(),
-                        mContext.getFeatureId());
+                handleSetTestProviderLocation();
                 return 0;
             }
             case "send-extra-command": {
-                String provider = getNextArgRequired();
-                String command = getNextArgRequired();
-                mService.sendExtraCommand(provider, command, null);
+                handleSendExtraCommand();
                 return 0;
             }
             default:
@@ -110,21 +95,47 @@
         }
     }
 
-    private int parseUserId() {
-        final String option = getNextOption();
-        if (option != null) {
-            if (option.equals("--user")) {
-                return UserHandle.parseUserArg(getNextArgRequired());
-            } else {
-                throw new IllegalArgumentException(
-                        "Expected \"--user\" option, but got \"" + option + "\" instead");
-            }
-        }
+    private void handleIsLocationEnabled() {
+        int userId = UserHandle.USER_CURRENT_OR_SELF;
 
-        return UserHandle.USER_CURRENT_OR_SELF;
+        do {
+            String option = getNextOption();
+            if (option == null) {
+                break;
+            }
+            if ("--user".equals(option)) {
+                userId = UserHandle.parseUserArg(getNextArgRequired());
+            } else {
+                throw new IllegalArgumentException("Unknown option: " + option);
+            }
+        } while (true);
+
+        getOutPrintWriter().println(mService.isLocationEnabledForUser(userId));
     }
 
-    private ProviderProperties parseTestProviderProviderProperties() {
+    private void handleSetLocationEnabled() {
+        boolean enabled = Boolean.parseBoolean(getNextArgRequired());
+
+        int userId = UserHandle.USER_CURRENT_OR_SELF;
+
+        do {
+            String option = getNextOption();
+            if (option == null) {
+                break;
+            }
+            if ("--user".equals(option)) {
+                userId = UserHandle.parseUserArg(getNextArgRequired());
+            } else {
+                throw new IllegalArgumentException("Unknown option: " + option);
+            }
+        } while (true);
+
+        mService.setLocationEnabledForUser(enabled, userId);
+    }
+
+    private void handleAddTestProvider() {
+        String provider = getNextArgRequired();
+
         boolean requiresNetwork = false;
         boolean requiresSatellite = false;
         boolean requiresCell = false;
@@ -135,8 +146,13 @@
         int powerRequirement = Criteria.POWER_LOW;
         int accuracy = Criteria.ACCURACY_FINE;
 
-        String option = getNextOption();
-        while (option != null) {
+        List<String> extraAttributionTags = Collections.emptyList();
+
+        do {
+            String option = getNextOption();
+            if (option == null) {
+                break;
+            }
             switch (option) {
                 case "--requiresNetwork": {
                     requiresNetwork = true;
@@ -174,12 +190,15 @@
                     accuracy = Integer.parseInt(getNextArgRequired());
                     break;
                 }
+                case "--extraAttributionTags": {
+                    extraAttributionTags = Arrays.asList(getNextArgRequired().split(","));
+                    break;
+                }
                 default:
                     throw new IllegalArgumentException(
                             "Received unexpected option: " + option);
             }
-            option = getNextOption();
-        }
+        } while(true);
 
         ProviderProperties properties = new ProviderProperties.Builder()
                 .setHasNetworkRequirement(requiresNetwork)
@@ -192,30 +211,50 @@
                 .setPowerUsage(powerRequirement)
                 .setAccuracy(accuracy)
                 .build();
-
-        return properties;
+        mService.addTestProvider(provider, properties, extraAttributionTags,
+                mContext.getOpPackageName(), mContext.getAttributionTag());
     }
 
-    private Location parseTestProviderLocation(String provider) {
-        boolean hasLatitude = false;
-        boolean hasLongitude = false;
+    private void handleRemoveTestProvider() {
+        String provider = getNextArgRequired();
+        mService.removeTestProvider(provider, mContext.getOpPackageName(),
+                mContext.getAttributionTag());
+    }
+
+    private void handleSetTestProviderEnabled() {
+        String provider = getNextArgRequired();
+        boolean enabled = Boolean.parseBoolean(getNextArgRequired());
+        mService.setTestProviderEnabled(provider, enabled, mContext.getOpPackageName(),
+                mContext.getAttributionTag());
+    }
+
+    private void handleSetTestProviderLocation() {
+        String provider = getNextArgRequired();
+
+        boolean hasLatLng = false;
 
         Location location = new Location(provider);
         location.setAccuracy(DEFAULT_TEST_LOCATION_ACCURACY);
         location.setTime(System.currentTimeMillis());
+        location.setElapsedRealtimeNanos(System.nanoTime());
 
-        String option = getNextOption();
-        while (option != null) {
+        do {
+            String option = getNextOption();
+            if (option == null) {
+                break;
+            }
             switch (option) {
                 case "--location": {
                     String[] locationInput = getNextArgRequired().split(",");
                     if (locationInput.length != 2) {
-                        throw new IllegalArgumentException(
-                                "Unexpected location format: " + Arrays.toString(locationInput));
+                        throw new IllegalArgumentException("Location argument must be in the form "
+                                + "of \"<LATITUDE>,<LONGITUDE>\", not "
+                                + Arrays.toString(locationInput));
                     }
 
                     location.setLatitude(Double.parseDouble(locationInput[0]));
                     location.setLongitude(Double.parseDouble(locationInput[1]));
+                    hasLatLng = true;
                     break;
                 }
                 case "--accuracy": {
@@ -227,15 +266,22 @@
                     break;
                 }
                 default:
-                    throw new IllegalArgumentException(
-                            "Received unexpected option: " + option);
+                    throw new IllegalArgumentException("Unknown option: " + option);
             }
-            option = getNextOption();
+        } while (true);
+
+        if (!hasLatLng) {
+            throw new IllegalArgumentException("Option \"--location\" is required");
         }
 
-        location.setElapsedRealtimeNanos(System.nanoTime());
+        mService.setTestProviderLocation(provider, location, mContext.getOpPackageName(),
+                mContext.getAttributionTag());
+    }
 
-        return location;
+    private void handleSendExtraCommand() {
+        String provider = getNextArgRequired();
+        String command = getNextArgRequired();
+        mService.sendExtraCommand(provider, command, null);
     }
 
     @Override
@@ -245,24 +291,29 @@
         pw.println("  help or -h");
         pw.println("    Print this help text.");
         pw.println("  is-location-enabled [--user <USER_ID>]");
-        pw.println("    Gets the master location switch enabled state.");
-        pw.println("  set-location-enabled [--user <USER_ID>] true|false");
-        pw.println("    Sets the master location switch enabled state.");
+        pw.println("    Gets the master location switch enabled state. If no user is specified,");
+        pw.println("    the current user is assumed.");
+        pw.println("  set-location-enabled true|false [--user <USER_ID>]");
+        pw.println("    Sets the master location switch enabled state. If no user is specified,");
+        pw.println("    the current user is assumed.");
         pw.println("  providers");
+        pw.println("    The providers command is followed by a subcommand, as listed below:");
+        pw.println();
         pw.println("    add-test-provider <PROVIDER> [--requiresNetwork] [--requiresSatellite]");
         pw.println("      [--requiresCell] [--hasMonetaryCost] [--supportsAltitude]");
         pw.println("      [--supportsSpeed] [--supportsBearing]");
         pw.println("      [--powerRequirement <POWER_REQUIREMENT>]");
+        pw.println("      [--extraAttributionTags <TAG>,<TAG>,...]");
         pw.println("      Add the given test provider. Requires MOCK_LOCATION permissions which");
         pw.println("      can be enabled by running \"adb shell appops set <uid>");
         pw.println("      android:mock_location allow\". There are optional flags that can be");
-        pw.println("      used to configure the provider properties. If no flags are included,");
-        pw.println("      then default values will be used.");
+        pw.println("      used to configure the provider properties and additional arguments. If");
+        pw.println("      no flags are included, then default values will be used.");
         pw.println("    remove-test-provider <PROVIDER>");
         pw.println("      Remove the given test provider.");
         pw.println("    set-test-provider-enabled <PROVIDER> true|false");
         pw.println("      Sets the given test provider enabled state.");
-        pw.println("    set-test-provider-location <PROVIDER> [--location <LATITUDE>,<LONGITUDE>]");
+        pw.println("    set-test-provider-location <PROVIDER> --location <LATITUDE>,<LONGITUDE>");
         pw.println("      [--accuracy <ACCURACY>] [--time <TIME>]");
         pw.println("      Set location for given test provider. Accuracy and time are optional.");
         pw.println("    send-extra-command <PROVIDER> <COMMAND>");
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index 81c1e45..dde45c4 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -295,7 +295,7 @@
                 };
             SensorPrivacyManager manager = SensorPrivacyManager.getInstance(mContext);
             manager.addSensorPrivacyListener(
-                    SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE, listener);
+                    SensorPrivacyManager.Sensors.MICROPHONE, listener);
         }
     }
 
@@ -1079,8 +1079,8 @@
      */
     private void sendMicrophoneDisableSettingUpdate() {
         SensorPrivacyManager manager = SensorPrivacyManager.getInstance(mContext);
-        boolean disabled = manager.isIndividualSensorPrivacyEnabled(
-                SensorPrivacyManager.INDIVIDUAL_SENSOR_MICROPHONE);
+        boolean disabled = manager.isSensorPrivacyEnabled(
+                SensorPrivacyManager.Sensors.MICROPHONE);
         Log.d(TAG, "Mic Disabled Setting: " + disabled);
         mContextHubWrapper.onMicrophoneDisableSettingChanged(disabled);
     }
diff --git a/services/core/java/com/android/server/location/countrydetector/ComprehensiveCountryDetector.java b/services/core/java/com/android/server/location/countrydetector/ComprehensiveCountryDetector.java
index af3907e..dda502b 100644
--- a/services/core/java/com/android/server/location/countrydetector/ComprehensiveCountryDetector.java
+++ b/services/core/java/com/android/server/location/countrydetector/ComprehensiveCountryDetector.java
@@ -320,13 +320,15 @@
                         "(source: " + detectedCountry.getSource()
                         + ", countryISO: " + detectedCountry.getCountryIso() + ")")
                     + " isAirplaneModeOff()=" + isAirplaneModeOff()
+                    + " isWifiOn()=" + isWifiOn()
                     + " mListener=" + mListener
                     + " isGeoCoderImplemnted()=" + isGeoCoderImplemented());
         }
 
         if (startLocationBasedDetection && (detectedCountry == null
                 || detectedCountry.getSource() > Country.COUNTRY_SOURCE_LOCATION)
-                && isAirplaneModeOff() && mListener != null && isGeoCoderImplemented()) {
+                && (isAirplaneModeOff() || isWifiOn()) && mListener != null
+                && isGeoCoderImplemented()) {
             if (DEBUG) Slog.d(TAG, "run startLocationBasedDetector()");
             // Start finding location when the source is less reliable than the
             // location and the airplane mode is off (as geocoder will not
@@ -387,6 +389,11 @@
                 mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) == 0;
     }
 
+    protected boolean isWifiOn() {
+        return Settings.Global.getInt(
+                mContext.getContentResolver(), Settings.Global.WIFI_ON, 0) != 0;
+    }
+
     /**
      * Notify the country change.
      */
diff --git a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
index dbfd0a5..29ce378 100644
--- a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
+++ b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
@@ -64,16 +64,17 @@
     private static final int EVENT_LOCATION_POWER_SAVE_MODE_CHANGE = 10;
 
     @GuardedBy("mAggregateStats")
-    private final ArrayMap<String, ArrayMap<String, AggregateStats>> mAggregateStats;
+    private final ArrayMap<String, ArrayMap<CallerIdentity, AggregateStats>> mAggregateStats;
 
     public LocationEventLog() {
         super(getLogSize());
         mAggregateStats = new ArrayMap<>(4);
     }
 
-    public ArrayMap<String, ArrayMap<String, AggregateStats>> copyAggregateStats() {
+    /** Copies out all aggregated stats. */
+    public ArrayMap<String, ArrayMap<CallerIdentity, AggregateStats>> copyAggregateStats() {
         synchronized (mAggregateStats) {
-            ArrayMap<String, ArrayMap<String, AggregateStats>> copy = new ArrayMap<>(
+            ArrayMap<String, ArrayMap<CallerIdentity, AggregateStats>> copy = new ArrayMap<>(
                     mAggregateStats);
             for (int i = 0; i < copy.size(); i++) {
                 copy.setValueAt(i, new ArrayMap<>(copy.valueAt(i)));
@@ -82,17 +83,18 @@
         }
     }
 
-    private AggregateStats getAggregateStats(String provider, String packageName) {
+    private AggregateStats getAggregateStats(String provider, CallerIdentity identity) {
         synchronized (mAggregateStats) {
-            ArrayMap<String, AggregateStats> packageMap = mAggregateStats.get(provider);
+            ArrayMap<CallerIdentity, AggregateStats> packageMap = mAggregateStats.get(provider);
             if (packageMap == null) {
                 packageMap = new ArrayMap<>(2);
                 mAggregateStats.put(provider, packageMap);
             }
-            AggregateStats stats = packageMap.get(packageName);
+            CallerIdentity stripped = identity.stripListenerId();
+            AggregateStats stats = packageMap.get(stripped);
             if (stats == null) {
                 stats = new AggregateStats();
-                packageMap.put(packageName, stats);
+                packageMap.put(stripped, stats);
             }
             return stats;
         }
@@ -117,34 +119,33 @@
     public void logProviderClientRegistered(String provider, CallerIdentity identity,
             LocationRequest request) {
         addLogEvent(EVENT_PROVIDER_REGISTER_CLIENT, provider, identity, request);
-        getAggregateStats(provider, identity.getPackageName())
-                .markRequestAdded(request.getIntervalMillis());
+        getAggregateStats(provider, identity).markRequestAdded(request.getIntervalMillis());
     }
 
     /** Logs a client unregistration for a location provider. */
     public void logProviderClientUnregistered(String provider, CallerIdentity identity) {
         addLogEvent(EVENT_PROVIDER_UNREGISTER_CLIENT, provider, identity);
-        getAggregateStats(provider, identity.getPackageName()).markRequestRemoved();
+        getAggregateStats(provider, identity).markRequestRemoved();
     }
 
     /** Logs a client for a location provider entering the active state. */
     public void logProviderClientActive(String provider, CallerIdentity identity) {
-        getAggregateStats(provider, identity.getPackageName()).markRequestActive();
+        getAggregateStats(provider, identity).markRequestActive();
     }
 
     /** Logs a client for a location provider leaving the active state. */
     public void logProviderClientInactive(String provider, CallerIdentity identity) {
-        getAggregateStats(provider, identity.getPackageName()).markRequestInactive();
+        getAggregateStats(provider, identity).markRequestInactive();
     }
 
     /** Logs a client for a location provider entering the foreground state. */
     public void logProviderClientForeground(String provider, CallerIdentity identity) {
-        getAggregateStats(provider, identity.getPackageName()).markRequestForeground();
+        getAggregateStats(provider, identity).markRequestForeground();
     }
 
     /** Logs a client for a location provider leaving the foreground state. */
     public void logProviderClientBackground(String provider, CallerIdentity identity) {
-        getAggregateStats(provider, identity.getPackageName()).markRequestBackground();
+        getAggregateStats(provider, identity).markRequestBackground();
     }
 
     /** Logs a change to the provider request for a location provider. */
@@ -165,7 +166,7 @@
         if (Build.IS_DEBUGGABLE || D) {
             addLogEvent(EVENT_PROVIDER_DELIVER_LOCATION, provider, numLocations, identity);
         }
-        getAggregateStats(provider, identity.getPackageName()).markLocationDelivered();
+        getAggregateStats(provider, identity).markLocationDelivered();
     }
 
     /** Logs that a provider has entered or exited stationary throttling. */
@@ -218,7 +219,7 @@
 
         protected final String mProvider;
 
-        protected ProviderEvent(long timeDelta, String provider) {
+        ProviderEvent(long timeDelta, String provider) {
             super(timeDelta);
             mProvider = provider;
         }
@@ -234,7 +235,7 @@
         private final int mUserId;
         private final boolean mEnabled;
 
-        protected ProviderEnabledEvent(long timeDelta, String provider, int userId,
+        ProviderEnabledEvent(long timeDelta, String provider, int userId,
                 boolean enabled) {
             super(timeDelta, provider);
             mUserId = userId;
@@ -252,7 +253,7 @@
 
         private final boolean mMocked;
 
-        protected ProviderMockedEvent(long timeDelta, String provider, boolean mocked) {
+        ProviderMockedEvent(long timeDelta, String provider, boolean mocked) {
             super(timeDelta, provider);
             mMocked = mocked;
         }
@@ -273,7 +274,7 @@
         private final CallerIdentity mIdentity;
         @Nullable private final LocationRequest mLocationRequest;
 
-        private ProviderRegisterEvent(long timeDelta, String provider, boolean registered,
+        ProviderRegisterEvent(long timeDelta, String provider, boolean registered,
                 CallerIdentity identity, @Nullable LocationRequest locationRequest) {
             super(timeDelta, provider);
             mRegistered = registered;
@@ -296,7 +297,7 @@
 
         private final ProviderRequest mRequest;
 
-        private ProviderUpdateEvent(long timeDelta, String provider, ProviderRequest request) {
+        ProviderUpdateEvent(long timeDelta, String provider, ProviderRequest request) {
             super(timeDelta, provider);
             mRequest = request;
         }
@@ -311,7 +312,7 @@
 
         private final int mNumLocations;
 
-        private ProviderReceiveLocationEvent(long timeDelta, String provider, int numLocations) {
+        ProviderReceiveLocationEvent(long timeDelta, String provider, int numLocations) {
             super(timeDelta, provider);
             mNumLocations = numLocations;
         }
@@ -327,7 +328,7 @@
         private final int mNumLocations;
         @Nullable private final CallerIdentity mIdentity;
 
-        private ProviderDeliverLocationEvent(long timeDelta, String provider, int numLocations,
+        ProviderDeliverLocationEvent(long timeDelta, String provider, int numLocations,
                 @Nullable CallerIdentity identity) {
             super(timeDelta, provider);
             mNumLocations = numLocations;
@@ -345,7 +346,7 @@
 
         private final boolean mStationaryThrottled;
 
-        private ProviderStationaryThrottledEvent(long timeDelta, String provider,
+        ProviderStationaryThrottledEvent(long timeDelta, String provider,
                 boolean stationaryThrottled) {
             super(timeDelta, provider);
             mStationaryThrottled = stationaryThrottled;
@@ -363,7 +364,7 @@
         @LocationPowerSaveMode
         private final int mLocationPowerSaveMode;
 
-        private LocationPowerSaveModeEvent(long timeDelta,
+        LocationPowerSaveModeEvent(long timeDelta,
                 @LocationPowerSaveMode int locationPowerSaveMode) {
             super(timeDelta);
             mLocationPowerSaveMode = locationPowerSaveMode;
@@ -401,7 +402,7 @@
         private final int mUserId;
         private final boolean mEnabled;
 
-        private LocationEnabledEvent(long timeDelta, int userId, boolean enabled) {
+        LocationEnabledEvent(long timeDelta, int userId, boolean enabled) {
             super(timeDelta);
             mUserId = userId;
             mEnabled = enabled;
diff --git a/services/core/java/com/android/server/location/geofence/GeofenceProxy.java b/services/core/java/com/android/server/location/geofence/GeofenceProxy.java
index bdfa6d7..c707149 100644
--- a/services/core/java/com/android/server/location/geofence/GeofenceProxy.java
+++ b/services/core/java/com/android/server/location/geofence/GeofenceProxy.java
@@ -29,7 +29,7 @@
 import android.os.UserHandle;
 import android.util.Log;
 
-import com.android.server.ServiceWatcher;
+import com.android.server.servicewatcher.ServiceWatcher;
 
 import java.util.Objects;
 
diff --git a/services/core/java/com/android/server/location/gnss/GnssAntennaInfoProvider.java b/services/core/java/com/android/server/location/gnss/GnssAntennaInfoProvider.java
new file mode 100644
index 0000000..1967e02
--- /dev/null
+++ b/services/core/java/com/android/server/location/gnss/GnssAntennaInfoProvider.java
@@ -0,0 +1,144 @@
+/*
+ * 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.location.gnss;
+
+import static com.android.server.location.gnss.GnssManagerService.TAG;
+
+import android.annotation.Nullable;
+import android.location.GnssAntennaInfo;
+import android.location.IGnssAntennaInfoListener;
+import android.location.util.identity.CallerIdentity;
+import android.os.Binder;
+import android.os.IBinder;
+
+import com.android.server.location.gnss.hal.GnssNative;
+import com.android.server.location.listeners.BinderListenerRegistration;
+import com.android.server.location.listeners.ListenerMultiplexer;
+import com.android.server.location.listeners.ListenerRegistration;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Antenna info HAL module and listener multiplexer.
+ */
+public class GnssAntennaInfoProvider extends
+        ListenerMultiplexer<IBinder, IGnssAntennaInfoListener,
+                ListenerRegistration<IGnssAntennaInfoListener>, Void> implements
+        GnssNative.BaseCallbacks, GnssNative.AntennaInfoCallbacks {
+
+    /**
+     * Registration object for GNSS listeners.
+     */
+    protected class AntennaInfoListenerRegistration extends
+            BinderListenerRegistration<Void, IGnssAntennaInfoListener> {
+
+        protected AntennaInfoListenerRegistration(CallerIdentity callerIdentity,
+                IGnssAntennaInfoListener listener) {
+            super(null, callerIdentity, listener);
+        }
+
+        @Override
+        protected GnssAntennaInfoProvider getOwner() {
+            return GnssAntennaInfoProvider.this;
+        }
+    }
+
+    private final GnssNative mGnssNative;
+
+    private volatile @Nullable List<GnssAntennaInfo> mAntennaInfos;
+
+    GnssAntennaInfoProvider(GnssNative gnssNative) {
+        mGnssNative = gnssNative;
+        mGnssNative.addBaseCallbacks(this);
+        mGnssNative.addAntennaInfoCallbacks(this);
+    }
+
+    @Nullable List<GnssAntennaInfo> getAntennaInfos() {
+        return mAntennaInfos;
+    }
+
+    @Override
+    public String getTag() {
+        return TAG;
+    }
+
+    public boolean isSupported() {
+        return mGnssNative.isAntennaInfoSupported();
+    }
+
+    public void addListener(CallerIdentity callerIdentity, IGnssAntennaInfoListener listener) {
+        long identity = Binder.clearCallingIdentity();
+        try {
+            putRegistration(listener.asBinder(),
+                    new AntennaInfoListenerRegistration(callerIdentity, listener));
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    public void removeListener(IGnssAntennaInfoListener listener) {
+        long identity = Binder.clearCallingIdentity();
+        try {
+            removeRegistration(listener.asBinder());
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    protected boolean registerWithService(Void merged,
+            Collection<ListenerRegistration<IGnssAntennaInfoListener>> listenerRegistrations) {
+        return true;
+    }
+
+    @Override
+    protected void unregisterWithService() {}
+
+    @Override
+    protected boolean isActive(ListenerRegistration<IGnssAntennaInfoListener> registration) {
+        return true;
+    }
+
+    @Override
+    protected Void mergeRegistrations(
+            Collection<ListenerRegistration<IGnssAntennaInfoListener>> listenerRegistrations) {
+        return null;
+    }
+
+    @Override
+    public void onHalStarted() {
+        mGnssNative.startAntennaInfoListening();
+    }
+
+    @Override
+    public void onHalRestarted() {
+        mGnssNative.startAntennaInfoListening();
+    }
+
+    @Override
+    public void onReportAntennaInfo(List<GnssAntennaInfo> antennaInfos) {
+        if (antennaInfos.equals(mAntennaInfos)) {
+            return;
+        }
+
+        mAntennaInfos = antennaInfos;
+        deliverToListeners(listener -> {
+            listener.onGnssAntennaInfoChanged(antennaInfos);
+        });
+    }
+}
diff --git a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
index 87e6ef4..5e6ae68 100644
--- a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
+++ b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
@@ -229,7 +229,7 @@
      * registrations will be treated as inactive and the backing service will never be registered.
      *
      */
-    protected boolean isServiceSupported() {
+    public boolean isSupported() {
         return true;
     }
 
@@ -276,7 +276,7 @@
 
     @Override
     protected boolean isActive(GnssListenerRegistration registration) {
-        if (!isServiceSupported()) {
+        if (!isSupported()) {
             return false;
         }
 
@@ -339,7 +339,7 @@
 
     @Override
     protected void onRegister() {
-        if (!isServiceSupported()) {
+        if (!isSupported()) {
             return;
         }
 
@@ -356,7 +356,7 @@
 
     @Override
     protected void onUnregister() {
-        if (!isServiceSupported()) {
+        if (!isSupported()) {
             return;
         }
 
@@ -404,7 +404,7 @@
 
     @Override
     protected String getServiceState() {
-        if (!isServiceSupported()) {
+        if (!isSupported()) {
             return "unsupported";
         } else {
             return super.getServiceState();
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index 9216a6b..1df29ab 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -103,6 +103,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
@@ -371,7 +372,8 @@
 
     public GnssLocationProvider(Context context, Injector injector, GnssNative gnssNative,
             GnssMetrics gnssMetrics) {
-        super(FgThread.getExecutor(), CallerIdentity.fromContext(context), PROPERTIES);
+        super(FgThread.getExecutor(), CallerIdentity.fromContext(context), PROPERTIES,
+                Collections.emptySet());
 
         mContext = context;
         mGnssNative = gnssNative;
diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
index 8312c63..bcdfed4 100644
--- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java
+++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
@@ -27,6 +27,7 @@
 import android.location.GnssCapabilities;
 import android.location.GnssMeasurementCorrections;
 import android.location.GnssMeasurementRequest;
+import android.location.IGnssAntennaInfoListener;
 import android.location.IGnssMeasurementsListener;
 import android.location.IGnssNavigationMessageListener;
 import android.location.IGnssNmeaListener;
@@ -49,7 +50,6 @@
 import com.android.server.location.injector.Injector;
 
 import java.io.FileDescriptor;
-import java.util.ArrayList;
 import java.util.List;
 
 /** Manages Gnss providers and related Gnss functions for LocationManagerService. */
@@ -68,11 +68,11 @@
     private final GnssNmeaProvider mGnssNmeaProvider;
     private final GnssMeasurementsProvider mGnssMeasurementsProvider;
     private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
+    private final GnssAntennaInfoProvider mGnssAntennaInfoProvider;
     private final IGpsGeofenceHardware mGnssGeofenceProxy;
 
     private final GnssGeofenceHalModule mGeofenceHalModule;
     private final GnssCapabilitiesHalModule mCapabilitiesHalModule;
-    private final GnssAntennaInfoHalModule mAntennaInfoHalModule;
 
     private final GnssMetrics mGnssMetrics;
 
@@ -89,11 +89,11 @@
         mGnssNmeaProvider = new GnssNmeaProvider(injector, mGnssNative);
         mGnssMeasurementsProvider = new GnssMeasurementsProvider(injector, mGnssNative);
         mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(injector, mGnssNative);
+        mGnssAntennaInfoProvider = new GnssAntennaInfoProvider(mGnssNative);
         mGnssGeofenceProxy = new GnssGeofenceProxy(mGnssNative);
 
         mGeofenceHalModule = new GnssGeofenceHalModule(mGnssNative);
         mCapabilitiesHalModule = new GnssCapabilitiesHalModule(mGnssNative);
-        mAntennaInfoHalModule = new GnssAntennaInfoHalModule(mGnssNative);
 
         // allow gnss access to begin - we must assume that callbacks can start immediately
         mGnssNative.register();
@@ -140,7 +140,7 @@
      * Get GNSS antenna information.
      */
     public @Nullable List<GnssAntennaInfo> getGnssAntennaInfos() {
-        return mAntennaInfoHalModule.getAntennaInfos();
+        return mGnssAntennaInfoProvider.getAntennaInfos();
     }
 
     /**
@@ -242,6 +242,24 @@
     }
 
     /**
+     * Adds a GNSS antenna info listener.
+     */
+    public void addGnssAntennaInfoListener(IGnssAntennaInfoListener listener, String packageName,
+            @Nullable String attributionTag, String listenerId) {
+
+        CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
+                listenerId);
+        mGnssAntennaInfoProvider.addListener(identity, listener);
+    }
+
+    /**
+     * Removes a GNSS antenna info listener.
+     */
+    public void removeGnssAntennaInfoListener(IGnssAntennaInfoListener listener) {
+        mGnssAntennaInfoProvider.removeListener(listener);
+    }
+
+    /**
      * Send Ni Response, indicating a location request initiated by a network carrier.
      */
     public void sendNiResponse(int notifId, int userResponse) {
@@ -263,25 +281,34 @@
 
         ipw.println("Capabilities: " + mGnssNative.getCapabilities());
 
-        List<GnssAntennaInfo> infos = mAntennaInfoHalModule.getAntennaInfos();
-        if (infos != null) {
-            ipw.println("Antenna Infos: " + infos);
+        if (mGnssStatusProvider.isSupported()) {
+            ipw.println("Status Provider:");
+            ipw.increaseIndent();
+            mGnssStatusProvider.dump(fd, ipw, args);
+            ipw.decreaseIndent();
         }
 
-        ipw.println("Measurements Provider:");
-        ipw.increaseIndent();
-        mGnssMeasurementsProvider.dump(fd, ipw, args);
-        ipw.decreaseIndent();
+        if (mGnssMeasurementsProvider.isSupported()) {
+            ipw.println("Measurements Provider:");
+            ipw.increaseIndent();
+            mGnssMeasurementsProvider.dump(fd, ipw, args);
+            ipw.decreaseIndent();
+        }
 
-        ipw.println("Navigation Message Provider:");
-        ipw.increaseIndent();
-        mGnssNavigationMessageProvider.dump(fd, ipw, args);
-        ipw.decreaseIndent();
+        if (mGnssNavigationMessageProvider.isSupported()) {
+            ipw.println("Navigation Message Provider:");
+            ipw.increaseIndent();
+            mGnssNavigationMessageProvider.dump(fd, ipw, args);
+            ipw.decreaseIndent();
+        }
 
-        ipw.println("Status Provider:");
-        ipw.increaseIndent();
-        mGnssStatusProvider.dump(fd, ipw, args);
-        ipw.decreaseIndent();
+        if (mGnssAntennaInfoProvider.isSupported()) {
+            ipw.println("Navigation Message Provider:");
+            ipw.increaseIndent();
+            ipw.println("Antenna Infos: " + mGnssAntennaInfoProvider.getAntennaInfos());
+            mGnssAntennaInfoProvider.dump(fd, ipw, args);
+            ipw.decreaseIndent();
+        }
 
         GnssPowerStats powerStats = mGnssNative.getPowerStats();
         if (powerStats != null) {
@@ -399,53 +426,4 @@
             }
         }
     }
-
-    private class GnssAntennaInfoHalModule implements GnssNative.BaseCallbacks,
-            GnssNative.AntennaInfoCallbacks {
-
-        private final GnssNative mGnssNative;
-
-        private volatile @Nullable List<GnssAntennaInfo> mAntennaInfos;
-
-        GnssAntennaInfoHalModule(GnssNative gnssNative) {
-            mGnssNative = gnssNative;
-            mGnssNative.addBaseCallbacks(this);
-            mGnssNative.addAntennaInfoCallbacks(this);
-        }
-
-        @Nullable List<GnssAntennaInfo> getAntennaInfos() {
-            return mAntennaInfos;
-        }
-
-        @Override
-        public void onHalStarted() {
-            mGnssNative.startAntennaInfoListening();
-        }
-
-        @Override
-        public void onHalRestarted() {
-            mGnssNative.startAntennaInfoListening();
-        }
-
-        @Override
-        public void onReportAntennaInfo(List<GnssAntennaInfo> antennaInfos) {
-            if (antennaInfos.equals(mAntennaInfos)) {
-                return;
-            }
-
-            mAntennaInfos = antennaInfos;
-
-            long ident = Binder.clearCallingIdentity();
-            try {
-                Intent intent = new Intent(LocationManager.ACTION_GNSS_ANTENNA_INFOS_CHANGED)
-                        .putParcelableArrayListExtra(LocationManager.EXTRA_GNSS_ANTENNA_INFOS,
-                                new ArrayList<>(antennaInfos))
-                        .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
-                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-                mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
index 305bc9b..b3119d7 100644
--- a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
@@ -99,7 +99,7 @@
     }
 
     @Override
-    protected boolean isServiceSupported() {
+    public boolean isSupported() {
         return mGnssNative.isMeasurementSupported();
     }
 
diff --git a/services/core/java/com/android/server/location/gnss/GnssNavigationMessageProvider.java b/services/core/java/com/android/server/location/gnss/GnssNavigationMessageProvider.java
index ff9ad65..e9fce05 100644
--- a/services/core/java/com/android/server/location/gnss/GnssNavigationMessageProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssNavigationMessageProvider.java
@@ -70,7 +70,7 @@
     }
 
     @Override
-    protected boolean isServiceSupported() {
+    public boolean isSupported() {
         return mGnssNative.isNavigationMessageCollectionSupported();
     }
 
diff --git a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
index 7e2f089..f275663 100644
--- a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
+++ b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
@@ -699,11 +699,11 @@
     }
 
     /**
-     * Returns true if antenna info listening is supported.
+     * Returns true if antenna info is supported.
      */
-    public boolean isAntennaInfoListeningSupported() {
+    public boolean isAntennaInfoSupported() {
         Preconditions.checkState(mRegistered);
-        return mGnssHal.isAntennaInfoListeningSupported();
+        return mGnssHal.isAntennaInfoSupported();
     }
 
     /**
@@ -1259,7 +1259,7 @@
             return native_stop_navigation_message_collection();
         }
 
-        protected boolean isAntennaInfoListeningSupported() {
+        protected boolean isAntennaInfoSupported() {
             return native_is_antenna_info_supported();
         }
 
diff --git a/services/core/java/com/android/server/location/provider/AbstractLocationProvider.java b/services/core/java/com/android/server/location/provider/AbstractLocationProvider.java
index 4e0a0b8..ba7f44f 100644
--- a/services/core/java/com/android/server/location/provider/AbstractLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/AbstractLocationProvider.java
@@ -28,7 +28,9 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.Collections;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.UnaryOperator;
@@ -65,9 +67,10 @@
 
         /**
          * Default state value for a location provider that is disabled with no properties and an
-         * empty provider package list.
+         * empty extra attribution tag set.
          */
-        public static final State EMPTY_STATE = new State(false, null, null);
+        public static final State EMPTY_STATE = new State(false, null, null,
+                Collections.emptySet());
 
         /**
          * The provider's allowed state.
@@ -84,10 +87,18 @@
          */
         @Nullable public final CallerIdentity identity;
 
-        private State(boolean allowed, ProviderProperties properties, CallerIdentity identity) {
+        /**
+         * A set of attribution tags also associated with this provider - these attribution tags may
+         * be afforded special privileges.
+         */
+        public final Set<String> extraAttributionTags;
+
+        private State(boolean allowed, ProviderProperties properties, CallerIdentity identity,
+                Set<String> extraAttributionTags) {
             this.allowed = allowed;
             this.properties = properties;
             this.identity = identity;
+            this.extraAttributionTags = Objects.requireNonNull(extraAttributionTags);
         }
 
         /**
@@ -97,7 +108,7 @@
             if (allowed == this.allowed) {
                 return this;
             } else {
-                return new State(allowed, properties, identity);
+                return new State(allowed, properties, identity, extraAttributionTags);
             }
         }
 
@@ -108,7 +119,7 @@
             if (Objects.equals(properties, this.properties)) {
                 return this;
             } else {
-                return new State(allowed, properties, identity);
+                return new State(allowed, properties, identity, extraAttributionTags);
             }
         }
 
@@ -119,10 +130,22 @@
             if (Objects.equals(identity, this.identity)) {
                 return this;
             } else {
-                return new State(allowed, properties, identity);
+                return new State(allowed, properties, identity, extraAttributionTags);
             }
         }
 
+        /**
+         * Returns a state the same as the current but with extra attribution tags set as specified.
+         */
+        public State withExtraAttributionTags(Set<String> extraAttributionTags) {
+            if (extraAttributionTags.equals(this.extraAttributionTags)) {
+                return this;
+            } else {
+                return new State(allowed, properties, identity, extraAttributionTags);
+            }
+        }
+
+
         @Override
         public boolean equals(Object o) {
             if (this == o) {
@@ -133,12 +156,13 @@
             }
             State state = (State) o;
             return allowed == state.allowed && properties == state.properties
-                    && Objects.equals(identity, state.identity);
+                    && Objects.equals(identity, state.identity)
+                    && extraAttributionTags.equals(state.extraAttributionTags);
         }
 
         @Override
         public int hashCode() {
-            return Objects.hash(allowed, properties, identity);
+            return Objects.hash(allowed, properties, identity, extraAttributionTags);
         }
     }
 
@@ -195,10 +219,14 @@
      * An optional identity and properties may be provided to initialize the location provider.
      */
     protected AbstractLocationProvider(Executor executor, @Nullable CallerIdentity identity,
-            @Nullable ProviderProperties properties) {
-        mExecutor = executor;
+            @Nullable ProviderProperties properties, Set<String> extraAttributionTags) {
+        Preconditions.checkArgument(identity == null || identity.getListenerId() == null);
+        mExecutor = Objects.requireNonNull(executor);
         mInternalState = new AtomicReference<>(new InternalState(null,
-                State.EMPTY_STATE.withIdentity(identity).withProperties(properties)));
+                State.EMPTY_STATE
+                        .withIdentity(identity)
+                        .withProperties(properties)
+                        .withExtraAttributionTags(extraAttributionTags)));
         mController = new Controller();
     }
 
@@ -270,13 +298,21 @@
     }
 
     /**
-     * Call this method to report a change in provider packages.
+     * Call this method to report a change in the provider's identity.
      */
     protected void setIdentity(@Nullable CallerIdentity identity) {
+        Preconditions.checkArgument(identity == null || identity.getListenerId() == null);
         setState(state -> state.withIdentity(identity));
     }
 
     /**
+     * Call this method to report a change in the provider's extra attribution tags.
+     */
+    protected void setExtraAttributionTags(Set<String> extraAttributionTags) {
+        setState(state -> state.withExtraAttributionTags(extraAttributionTags));
+    }
+
+    /**
      * Call this method to report a new location.
      */
     protected void reportLocation(LocationResult locationResult) {
@@ -335,6 +371,8 @@
 
         private boolean mStarted = false;
 
+        Controller() {}
+
         @Override
         public State setListener(@Nullable Listener listener) {
             InternalState oldInternalState = mInternalState.getAndUpdate(
diff --git a/services/core/java/com/android/server/location/provider/DelegateLocationProvider.java b/services/core/java/com/android/server/location/provider/DelegateLocationProvider.java
index a3ec867..423f833 100644
--- a/services/core/java/com/android/server/location/provider/DelegateLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/DelegateLocationProvider.java
@@ -24,6 +24,7 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.Collections;
 import java.util.concurrent.Executor;
 
 /**
@@ -40,7 +41,7 @@
     private boolean mInitialized = false;
 
     DelegateLocationProvider(Executor executor, AbstractLocationProvider delegate) {
-        super(executor, null, null);
+        super(executor, null, null, Collections.emptySet());
 
         mDelegate = delegate;
     }
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index 388b5a4..2aa6f28 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -29,6 +29,8 @@
 import static android.os.PowerManager.LOCATION_MODE_FOREGROUND_ONLY;
 import static android.os.PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF;
 import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF;
+import static android.os.PowerWhitelistManager.REASON_LOCATION_PROVIDER;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
 
 import static com.android.server.location.LocationManagerService.D;
 import static com.android.server.location.LocationManagerService.TAG;
@@ -52,6 +54,8 @@
 import android.location.Location;
 import android.location.LocationManager;
 import android.location.LocationManagerInternal;
+import android.location.LocationManagerInternal.LocationTagInfo;
+import android.location.LocationManagerInternal.OnProviderLocationTagsChangeListener;
 import android.location.LocationManagerInternal.ProviderEnabledListener;
 import android.location.LocationRequest;
 import android.location.LocationResult;
@@ -85,6 +89,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.location.LocationPermissions;
@@ -117,6 +122,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Objects;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.function.Predicate;
@@ -223,7 +229,10 @@
             BroadcastOptions options = BroadcastOptions.makeBasic();
             options.setDontSendToRestrictedApps(true);
             // allows apps to start a fg service in response to a location PI
-            options.setTemporaryAppWhitelistDuration(TEMPORARY_APP_ALLOWLIST_DURATION_MS);
+            options.setTemporaryAppAllowlist(TEMPORARY_APP_ALLOWLIST_DURATION_MS,
+                    TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                    REASON_LOCATION_PROVIDER,
+                    "");
 
             Intent intent = new Intent().putExtra(KEY_LOCATION_CHANGED,
                     locationResult.getLastLocation());
@@ -304,6 +313,7 @@
                 LocationTransport transport, @PermissionLevel int permissionLevel) {
             super(Objects.requireNonNull(request), identity, transport);
 
+            Preconditions.checkArgument(identity.getListenerId() != null);
             Preconditions.checkArgument(permissionLevel > PERMISSION_NONE);
             Preconditions.checkArgument(!request.getWorkSource().isEmpty());
 
@@ -1287,6 +1297,9 @@
     @GuardedBy("mLock")
     private @Nullable OnAlarmListener mDelayedRegister;
 
+    @GuardedBy("mLock")
+    private @Nullable OnProviderLocationTagsChangeListener mOnLocationTagsChangeListener;
+
     public LocationProviderManager(Context context, Injector injector, LocationEventLog eventLog,
             String name, @Nullable PassiveLocationProviderManager passiveManager) {
         mContext = context;
@@ -1447,6 +1460,19 @@
         }
     }
 
+    /**
+     * Registers a listener for the location tags of the provider.
+     *
+     * @param listener The listener
+     */
+    public void setOnProviderLocationTagsChangeListener(
+            @Nullable OnProviderLocationTagsChangeListener listener) {
+        Preconditions.checkArgument(mOnLocationTagsChangeListener == null || listener == null);
+        synchronized (mLock) {
+            mOnLocationTagsChangeListener = listener;
+        }
+    }
+
     public void setMockProvider(@Nullable MockLocationProvider provider) {
         synchronized (mLock) {
             Preconditions.checkState(mState != STATE_STOPPED);
@@ -2243,6 +2269,27 @@
         if (oldState.allowed != newState.allowed) {
             onEnabledChanged(UserHandle.USER_ALL);
         }
+
+        if (mOnLocationTagsChangeListener != null) {
+            if (!oldState.extraAttributionTags.equals(newState.extraAttributionTags)) {
+                if (oldState.identity != null) {
+                    FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(
+                            OnProviderLocationTagsChangeListener::onLocationTagsChanged,
+                            mOnLocationTagsChangeListener, new LocationTagInfo(
+                                    oldState.identity.getUid(), oldState.identity.getPackageName(),
+                                    Collections.emptySet())
+                            ));
+                }
+                if (newState.identity != null) {
+                    FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(
+                            OnProviderLocationTagsChangeListener::onLocationTagsChanged,
+                            mOnLocationTagsChangeListener, new LocationTagInfo(
+                                    newState.identity.getUid(), newState.identity.getPackageName(),
+                                    newState.extraAttributionTags)
+                            ));
+                }
+            }
+        }
     }
 
     @GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/location/provider/MockLocationProvider.java b/services/core/java/com/android/server/location/provider/MockLocationProvider.java
index 0d8f643..52b04d4 100644
--- a/services/core/java/com/android/server/location/provider/MockLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/MockLocationProvider.java
@@ -28,6 +28,7 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.Set;
 
 /**
  * A mock location provider used by LocationManagerService to implement test providers.
@@ -38,9 +39,10 @@
 
     @Nullable private Location mLocation;
 
-    public MockLocationProvider(ProviderProperties properties, CallerIdentity identity) {
+    public MockLocationProvider(ProviderProperties properties, CallerIdentity identity,
+            Set<String> extraAttributionTags) {
         // using a direct executor is ok because this class has no locks that could deadlock
-        super(DIRECT_EXECUTOR, identity, properties);
+        super(DIRECT_EXECUTOR, identity, properties, extraAttributionTags);
     }
 
     /** Sets the allowed state of this mock provider. */
diff --git a/services/core/java/com/android/server/location/provider/MockableLocationProvider.java b/services/core/java/com/android/server/location/provider/MockableLocationProvider.java
index cb7264e..8193644 100644
--- a/services/core/java/com/android/server/location/provider/MockableLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/MockableLocationProvider.java
@@ -31,6 +31,7 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.Collections;
 
 /**
  * Represents a location provider that may switch between a mock implementation and a real
@@ -75,7 +76,7 @@
     public MockableLocationProvider(Object ownerLock) {
         // using a direct executor is acceptable because all inbound calls are delegated to the
         // actual provider implementations which will use their own executors
-        super(DIRECT_EXECUTOR, null, null);
+        super(DIRECT_EXECUTOR, null, null, Collections.emptySet());
         mOwnerLock = ownerLock;
         mRequest = ProviderRequest.EMPTY_REQUEST;
     }
diff --git a/services/core/java/com/android/server/location/provider/PassiveLocationProvider.java b/services/core/java/com/android/server/location/provider/PassiveLocationProvider.java
index a5758a3..68ede88 100644
--- a/services/core/java/com/android/server/location/provider/PassiveLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/PassiveLocationProvider.java
@@ -30,6 +30,7 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.Collections;
 
 /**
  * A passive location provider reports locations received from other providers
@@ -47,7 +48,8 @@
 
     public PassiveLocationProvider(Context context) {
         // using a direct executor is ok because this class has no locks that could deadlock
-        super(DIRECT_EXECUTOR, CallerIdentity.fromContext(context), PROPERTIES);
+        super(DIRECT_EXECUTOR, CallerIdentity.fromContext(context), PROPERTIES,
+                Collections.emptySet());
         setAllowed(true);
     }
 
diff --git a/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java b/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
index 4c97f64..c86e49b 100644
--- a/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
@@ -32,15 +32,18 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.util.ArraySet;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.ArrayUtils;
-import com.android.server.ServiceWatcher;
 import com.android.server.location.provider.AbstractLocationProvider;
+import com.android.server.servicewatcher.ServiceWatcher;
+import com.android.server.servicewatcher.ServiceWatcher.BoundService;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 
@@ -49,6 +52,9 @@
  */
 public class ProxyLocationProvider extends AbstractLocationProvider {
 
+    private static final String KEY_EXTRA_ATTRIBUTION_TAGS = "android:location_allow_listed_tags";
+    private static final String EXTRA_ATTRIBUTION_TAGS_SEPARATOR = ";";
+
     /**
      * Creates and registers this proxy. If no suitable service is available for the proxy, returns
      * null.
@@ -84,7 +90,7 @@
             int nonOverlayPackageResId) {
         // safe to use direct executor since our locks are not acquired in a code path invoked by
         // our owning provider
-        super(DIRECT_EXECUTOR, null, null);
+        super(DIRECT_EXECUTOR, null, null, Collections.emptySet());
 
         mContext = context;
         mServiceWatcher = new ServiceWatcher(context, action, this::onBind,
@@ -98,12 +104,22 @@
         return mServiceWatcher.checkServiceResolves();
     }
 
-    private void onBind(IBinder binder, ComponentName service) throws RemoteException {
+    private void onBind(IBinder binder, BoundService boundService) throws RemoteException {
         ILocationProvider provider = ILocationProvider.Stub.asInterface(binder);
 
         synchronized (mLock) {
             mProxy = new Proxy();
-            mService = service;
+            mService = boundService.component;
+
+            // update extra attribution tag info from manifest
+            if (boundService.metadata != null) {
+                String tagsList = boundService.metadata.getString(KEY_EXTRA_ATTRIBUTION_TAGS);
+                if (tagsList != null) {
+                    setExtraAttributionTags(
+                            new ArraySet<>(tagsList.split(EXTRA_ATTRIBUTION_TAGS_SEPARATOR)));
+                }
+            }
+
             provider.setLocationProviderManager(mProxy);
 
             ProviderRequest request = mRequest;
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 2dd5448..43c7365 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -479,8 +479,8 @@
             return KeyStore.getInstance();
         }
 
-        public RecoverableKeyStoreManager getRecoverableKeyStoreManager(KeyStore keyStore) {
-            return RecoverableKeyStoreManager.getInstance(mContext, keyStore);
+        public RecoverableKeyStoreManager getRecoverableKeyStoreManager() {
+            return RecoverableKeyStoreManager.getInstance(mContext);
         }
 
         public IStorageManager getStorageManager() {
@@ -561,7 +561,7 @@
         mInjector = injector;
         mContext = injector.getContext();
         mKeyStore = injector.getKeyStore();
-        mRecoverableKeyStoreManager = injector.getRecoverableKeyStoreManager(mKeyStore);
+        mRecoverableKeyStoreManager = injector.getRecoverableKeyStoreManager();
         mHandler = injector.getHandler(injector.getServiceThread());
         mStrongAuth = injector.getStrongAuth();
         mActivityManager = injector.getActivityManager();
diff --git a/services/core/java/com/android/server/locksettings/OWNERS b/services/core/java/com/android/server/locksettings/OWNERS
index 08b8a8c..7577ee5 100644
--- a/services/core/java/com/android/server/locksettings/OWNERS
+++ b/services/core/java/com/android/server/locksettings/OWNERS
@@ -1,3 +1,4 @@
 jaggies@google.com
 kchyn@google.com
 rubinxu@google.com
+xunchang@google.com
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java
index b3b4546..697bf08 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java
@@ -44,7 +44,7 @@
      * Use the default lifetime of 10 minutes. The lifetime covers the following activities:
      * Server wrap secret -> device reboot -> server unwrap blob.
      */
-    private static final long DEFAULT_SERVER_BLOB_LIFETIME_IN_MILLIS = 600_1000;
+    private static final long DEFAULT_SERVER_BLOB_LIFETIME_IN_MILLIS = 600_000;
 
     private final LockSettingsStorage mStorage;
 
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeyStoreProxyImpl.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeyStoreProxyImpl.java
index 9857fb6..f594136 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeyStoreProxyImpl.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeyStoreProxyImpl.java
@@ -16,8 +16,6 @@
 
 package com.android.server.locksettings.recoverablekeystore;
 
-import android.security.keystore2.AndroidKeyStoreProvider;
-
 import java.io.IOException;
 import java.security.Key;
 import java.security.KeyStore;
@@ -31,24 +29,11 @@
  */
 public class KeyStoreProxyImpl implements KeyStoreProxy {
 
+    public static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
+
     private final KeyStore mKeyStore;
 
     /**
-     * TODO This function redirects keystore access to the legacy keystore during a transitional
-     *      phase during which not all calling code has been adjusted to use Keystore 2.0.
-     *      This can be reverted to a constant of "AndroidKeyStore" when b/171305684 is complete.
-     *      The specific bug for this component is b/171305545.
-     */
-    static String androidKeystoreProviderName() {
-        if (AndroidKeyStoreProvider.isInstalled()) {
-            return "AndroidKeyStoreLegacy";
-        } else {
-            return "AndroidKeyStore";
-        }
-
-    }
-
-    /**
      * A new instance, delegating to {@code keyStore}.
      */
     public KeyStoreProxyImpl(KeyStore keyStore) {
@@ -84,7 +69,7 @@
      * @throws KeyStoreException if there was a problem getting or initializing the key store.
      */
     public static KeyStore getAndLoadAndroidKeyStore() throws KeyStoreException {
-        KeyStore keyStore = KeyStore.getInstance(androidKeystoreProviderName());
+        KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);
         try {
             keyStore.load(/*param=*/ null);
         } catch (CertificateException | IOException | NoSuchAlgorithmException e) {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
index dff1df7..f448a6e 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
@@ -470,7 +470,7 @@
      * @throws KeyStoreException if there was a problem getting or initializing the key store.
      */
     private static KeyStore getAndLoadAndroidKeyStore() throws KeyStoreException {
-        KeyStore keyStore = KeyStore.getInstance(KeyStoreProxyImpl.androidKeystoreProviderName());
+        KeyStore keyStore = KeyStore.getInstance(KeyStoreProxyImpl.ANDROID_KEY_STORE_PROVIDER);
         try {
             keyStore.load(/*param=*/ null);
         } catch (CertificateException | IOException | NoSuchAlgorithmException e) {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index 6d97ed7..b49bced 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -34,7 +34,6 @@
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.os.UserHandle;
-import android.security.KeyStore;
 import android.security.keystore.recovery.KeyChainProtectionParams;
 import android.security.keystore.recovery.KeyChainSnapshot;
 import android.security.keystore.recovery.RecoveryCertPath;
@@ -110,14 +109,14 @@
      * @hide
      */
     public static synchronized RecoverableKeyStoreManager
-            getInstance(Context context, KeyStore keystore) {
+            getInstance(Context context) {
         if (mInstance == null) {
             RecoverableKeyStoreDb db = RecoverableKeyStoreDb.newInstance(context);
             PlatformKeyManager platformKeyManager;
             ApplicationKeyStorage applicationKeyStorage;
             try {
                 platformKeyManager = PlatformKeyManager.getInstance(context, db);
-                applicationKeyStorage = ApplicationKeyStorage.getInstance(keystore);
+                applicationKeyStorage = ApplicationKeyStorage.getInstance();
             } catch (NoSuchAlgorithmException e) {
                 // Impossible: all algorithms must be supported by AOSP
                 throw new RuntimeException(e);
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
index 84ddbf7..2398f56 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
@@ -21,9 +21,13 @@
 import android.annotation.Nullable;
 import android.os.ServiceSpecificException;
 import android.security.Credentials;
+import android.security.KeyStore;
+import android.security.KeyStore2;
 import android.security.keystore.KeyProperties;
 import android.security.keystore.KeyProtection;
-import android.security.KeyStore;
+import android.system.keystore2.Domain;
+import android.system.keystore2.KeyDescriptor;
+import android.system.keystore2.KeyPermission;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -47,32 +51,37 @@
 
     private static final String APPLICATION_KEY_ALIAS_PREFIX =
             "com.android.server.locksettings.recoverablekeystore/application/";
+    private static final String APPLICATION_KEY_GRANT_PREFIX = "recoverable_key:";
 
     private final KeyStoreProxy mKeyStore;
-    private final KeyStore mKeystoreService;
 
-    public static ApplicationKeyStorage getInstance(KeyStore keystoreService)
+    /**
+     * Creates a new instance.
+     */
+    public static ApplicationKeyStorage getInstance()
             throws KeyStoreException {
         return new ApplicationKeyStorage(
-                new KeyStoreProxyImpl(KeyStoreProxyImpl.getAndLoadAndroidKeyStore()),
-                keystoreService);
+                new KeyStoreProxyImpl(KeyStoreProxyImpl.getAndLoadAndroidKeyStore()));
     }
 
     @VisibleForTesting
-    ApplicationKeyStorage(KeyStoreProxy keyStore, KeyStore keystoreService) {
+    ApplicationKeyStorage(KeyStoreProxy keyStore) {
         mKeyStore = keyStore;
-        mKeystoreService = keystoreService;
     }
 
     /**
-     * Returns grant alias, valid in Applications namespace.
+     * Returns String representation of {@code KeyDescriptor} valid in application's namespace.
      */
     public @Nullable String getGrantAlias(int userId, int uid, String alias) {
-        // Aliases used by {@link KeyStore} are different than used by public API.
-        // {@code USER_PRIVATE_KEY} prefix is used secret keys.
         Log.i(TAG, String.format(Locale.US, "Get %d/%d/%s", userId, uid, alias));
-        String keystoreAlias = Credentials.USER_PRIVATE_KEY + getInternalAlias(userId, uid, alias);
-        return mKeystoreService.grant(keystoreAlias, uid);
+        String keystoreAlias = getInternalAlias(userId, uid, alias);
+        if (useKeyStore2()) {
+            return makeKeystoreEngineGrantString(uid, keystoreAlias);
+        } else {
+            // Aliases used by {@link KeyStore} are different than used by public API.
+            // {@code USER_PRIVATE_KEY} prefix is used secret keys.
+            return KeyStore.getInstance().grant(Credentials.USER_PRIVATE_KEY + keystoreAlias, uid);
+        }
     }
 
     public void setSymmetricKeyEntry(int userId, int uid, String alias, byte[] secretKey)
@@ -117,4 +126,31 @@
     private String getInternalAlias(int userId, int uid, String alias) {
         return APPLICATION_KEY_ALIAS_PREFIX + userId + "/" + uid + "/" + alias;
     }
+
+    private String makeKeystoreEngineGrantString(int uid, String alias) {
+        if (alias == null) {
+            return null;
+        }
+
+        KeyDescriptor key = new KeyDescriptor();
+        key.domain = Domain.APP;
+        key.nspace = KeyProperties.NAMESPACE_APPLICATION;
+        key.alias = alias;
+        key.blob = null;
+
+        int grantAccessVector = KeyPermission.USE | KeyPermission.GET_INFO | KeyPermission.DELETE;
+
+        try {
+            key = KeyStore2.getInstance().grant(key, uid, grantAccessVector);
+        } catch (android.security.KeyStoreException e) {
+            Log.e(TAG, "Failed to get grant for KeyStore key.", e);
+            throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
+        }
+        return String.format("%s%016X", APPLICATION_KEY_GRANT_PREFIX, key.nspace);
+    }
+
+    private static boolean useKeyStore2() {
+        return android.security.keystore2.AndroidKeyStoreProvider.isInstalled();
+    }
+
 }
diff --git a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
index 87e170a..cb0a6688 100644
--- a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
+++ b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
@@ -29,6 +29,7 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.os.Handler;
+import android.os.PowerWhitelistManager;
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Log;
@@ -195,8 +196,9 @@
         mediaButtonIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, callingPackageName);
 
         final BroadcastOptions options = BroadcastOptions.makeBasic();
-        options.setTemporaryAppWhitelistDuration(
-                FGS_STARTS_TEMP_ALLOWLIST_DURATION_MS);
+        options.setTemporaryAppAllowlist(FGS_STARTS_TEMP_ALLOWLIST_DURATION_MS,
+                PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                PowerWhitelistManager.REASON_MEDIA_BUTTON, "");
         if (mPendingIntent != null) {
             if (DEBUG_KEY_EVENT) {
                 Log.d(TAG, "Sending " + keyEvent + " to the last known PendingIntent "
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 18f2d84..23d8429 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -40,10 +40,10 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
-import android.content.pm.ParceledListSlice;
 import android.media.AudioManager;
 import android.media.AudioPlaybackConfiguration;
 import android.media.IRemoteSessionCallback;
+import android.media.MediaCommunicationManager;
 import android.media.Session2Token;
 import android.media.session.IActiveSessionsListener;
 import android.media.session.IOnMediaKeyEventDispatchedListener;
@@ -151,6 +151,25 @@
     private MediaSessionPolicyProvider mCustomMediaSessionPolicyProvider;
     private MediaKeyDispatcher mCustomMediaKeyDispatcher;
 
+    private MediaCommunicationManager mCommunicationManager;
+    private final MediaCommunicationManager.SessionCallback mSession2TokenCallback =
+            new MediaCommunicationManager.SessionCallback() {
+                @Override
+                public void onSession2TokenCreated(Session2Token token) {
+                    if (DEBUG) {
+                        Log.d(TAG, "Session2 is created " + token);
+                    }
+                    MediaSession2Record record = new MediaSession2Record(token,
+                            MediaSessionService.this, mRecordThread.getLooper(), 0);
+                    synchronized (mLock) {
+                        FullUserRecord user = getFullUserRecordLocked(record.getUserId());
+                        if (user != null) {
+                            user.mPriorityStack.addSession(record);
+                        }
+                    }
+                }
+            };
+
     public MediaSessionService(Context context) {
         super(context);
         mContext = context;
@@ -202,6 +221,19 @@
         mContext.registerReceiver(mNotificationListenerEnabledChangedReceiver, filter);
     }
 
+    @Override
+    public void onBootPhase(int phase) {
+        super.onBootPhase(phase);
+        switch (phase) {
+            // This ensures MediaCommunicationService is started
+            case PHASE_BOOT_COMPLETED:
+                mCommunicationManager = mContext.getSystemService(MediaCommunicationManager.class);
+                mCommunicationManager.registerSessionCallback(new HandlerExecutor(mHandler),
+                        mSession2TokenCallback);
+                break;
+        }
+    }
+
     private final BroadcastReceiver mNotificationListenerEnabledChangedReceiver =
             new BroadcastReceiver() {
                 @Override
@@ -1139,31 +1171,6 @@
         }
 
         @Override
-        public void notifySession2Created(Session2Token sessionToken) throws RemoteException {
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-            try {
-                if (DEBUG) {
-                    Log.d(TAG, "Session2 is created " + sessionToken);
-                }
-                if (uid != sessionToken.getUid()) {
-                    throw new SecurityException("Unexpected Session2Token's UID, expected=" + uid
-                            + " but actually=" + sessionToken.getUid());
-                }
-                MediaSession2Record record = new MediaSession2Record(sessionToken,
-                        MediaSessionService.this, mRecordThread.getLooper(), 0);
-                synchronized (mLock) {
-                    FullUserRecord user = getFullUserRecordLocked(record.getUserId());
-                    user.mPriorityStack.addSession(record);
-                }
-                // Do not immediately notify changes -- do so when framework can dispatch command
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
         public List<MediaSession.Token> getSessions(ComponentName componentName, int userId) {
             final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
@@ -1185,26 +1192,6 @@
         }
 
         @Override
-        public ParceledListSlice getSession2Tokens(int userId) {
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-
-            try {
-                // Check that they can make calls on behalf of the user and get the final user id
-                int resolvedUserId = handleIncomingUser(pid, uid, userId, null);
-                List<Session2Token> result;
-                synchronized (mLock) {
-                    FullUserRecord user = getFullUserRecordLocked(userId);
-                    result = user.mPriorityStack.getSession2Tokens(resolvedUserId);
-                }
-                return new ParceledListSlice(result);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
         public void addSessionsListener(IActiveSessionsListener listener,
                 ComponentName componentName, int userId) throws RemoteException {
             final int pid = Binder.getCallingPid();
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 3cc32be..851ea3d 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -35,7 +35,6 @@
 import android.net.NetworkInfo;
 import android.net.NetworkRequest;
 import android.os.Handler;
-import android.security.KeyStore;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -63,7 +62,6 @@
     @NonNull private final Handler mHandler;
     @NonNull private final Vpn mVpn;
     @NonNull private final VpnProfile mProfile;
-    @NonNull private final KeyStore mKeyStore;
 
     @NonNull private final Object mStateLock = new Object();
 
@@ -132,7 +130,6 @@
 
     public LockdownVpnTracker(@NonNull Context context,
             @NonNull Handler handler,
-            @NonNull KeyStore keyStore,
             @NonNull Vpn vpn,
             @NonNull VpnProfile profile) {
         mContext = Objects.requireNonNull(context);
@@ -140,7 +137,6 @@
         mHandler = Objects.requireNonNull(handler);
         mVpn = Objects.requireNonNull(vpn);
         mProfile = Objects.requireNonNull(profile);
-        mKeyStore = Objects.requireNonNull(keyStore);
         mNotificationManager = mContext.getSystemService(NotificationManager.class);
 
         final Intent configIntent = new Intent(ACTION_VPN_SETTINGS);
@@ -212,7 +208,7 @@
                 //    network is the system default. So, if the VPN  is up and underlying network
                 //    (e.g., wifi) disconnects, CS will inform apps that the VPN's capabilities have
                 //    changed to match the new default network (e.g., cell).
-                mVpn.startLegacyVpnPrivileged(mProfile, mKeyStore, network, egressProp);
+                mVpn.startLegacyVpnPrivileged(mProfile, network, egressProp);
             } catch (IllegalStateException e) {
                 mAcceptedEgressIface = null;
                 Log.e(TAG, "Failed to start VPN", e);
diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java
index bce8069..22ed781 100644
--- a/services/core/java/com/android/server/net/NetworkIdentitySet.java
+++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java
@@ -40,6 +40,7 @@
     private static final int VERSION_ADD_NETWORK_ID = 3;
     private static final int VERSION_ADD_METERED = 4;
     private static final int VERSION_ADD_DEFAULT_NETWORK = 5;
+    private static final int VERSION_ADD_OEM_MANAGED_NETWORK = 6;
 
     public NetworkIdentitySet() {
     }
@@ -84,13 +85,20 @@
                 defaultNetwork = true;
             }
 
+            final int oemNetCapabilities;
+            if (version >= VERSION_ADD_OEM_MANAGED_NETWORK) {
+                oemNetCapabilities = in.readInt();
+            } else {
+                oemNetCapabilities = NetworkIdentity.OEM_NONE;
+            }
+
             add(new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered,
-                    defaultNetwork));
+                    defaultNetwork, oemNetCapabilities));
         }
     }
 
     public void writeToStream(DataOutput out) throws IOException {
-        out.writeInt(VERSION_ADD_DEFAULT_NETWORK);
+        out.writeInt(VERSION_ADD_OEM_MANAGED_NETWORK);
         out.writeInt(size());
         for (NetworkIdentity ident : this) {
             out.writeInt(ident.getType());
@@ -100,6 +108,7 @@
             out.writeBoolean(ident.getRoaming());
             out.writeBoolean(ident.getMetered());
             out.writeBoolean(ident.getDefaultNetwork());
+            out.writeInt(ident.getOemManaged());
         }
     }
 
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index ecf4438..067c5c0e 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -54,6 +54,7 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkIdentity.OEM_NONE;
 import static android.net.NetworkPolicy.LIMIT_DISABLED;
 import static android.net.NetworkPolicy.SNOOZE_NEVER;
 import static android.net.NetworkPolicy.WARNING_DISABLED;
@@ -882,9 +883,10 @@
 
             mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
             try {
+                // TODO: There shouldn't be a need to receive callback for all changes.
                 mActivityManager.registerUidObserver(mUidObserver,
                         ActivityManager.UID_OBSERVER_PROCSTATE|ActivityManager.UID_OBSERVER_GONE,
-                        NetworkPolicyManager.FOREGROUND_THRESHOLD_STATE, "android");
+                        ActivityManager.PROCESS_STATE_UNKNOWN, "android");
                 mNetworkManager.registerObserver(mAlertObserver);
             } catch (RemoteException e) {
                 // ignored; both services live in system_server
@@ -1403,7 +1405,11 @@
             final String subscriberId = mSubIdToSubscriberId.valueAt(i);
             final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
                     TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true,
-                    true);
+                    true, OEM_NONE);
+            /* While OEM_NONE indicates "any non OEM managed network", OEM_NONE is meant to be a
+             * placeholder value here. The probeIdent is matched against a NetworkTemplate which
+             * should have its OEM managed value set to OEM_MANAGED_ALL, which will cause the
+             * template to match probeIdent without regard to OEM managed status. */
             if (template.matches(probeIdent)) {
                 return subId;
             }
@@ -1633,7 +1639,8 @@
         // find and update the mobile NetworkPolicy for this subscriber id
         boolean policyUpdated = false;
         final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
-                TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true, true);
+                TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true, true,
+                OEM_NONE);
         for (int i = mNetworkPolicy.size() - 1; i >= 0; i--) {
             final NetworkTemplate template = mNetworkPolicy.keyAt(i);
             if (template.matches(probeIdent)) {
@@ -1862,7 +1869,7 @@
 
                     final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
                             TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true,
-                            true);
+                            true, OEM_NONE);
                     // Template is matched when subscriber id matches.
                     if (template.matches(probeIdent)) {
                         matchingSubIds.add(subId);
@@ -2177,7 +2184,8 @@
     private boolean ensureActiveMobilePolicyAL(int subId, String subscriberId) {
         // Poke around to see if we already have a policy
         final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
-                TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true, true);
+                TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true, true,
+                OEM_NONE);
         for (int i = mNetworkPolicy.size() - 1; i >= 0; i--) {
             final NetworkTemplate template = mNetworkPolicy.keyAt(i);
             if (template.matches(probeIdent)) {
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 6aefe41..557fa89 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -54,6 +54,8 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FastDataInput;
+import com.android.internal.util.FastDataOutput;
 import com.android.internal.util.FileRotator;
 import com.android.internal.util.IndentingPrintWriter;
 
@@ -89,6 +91,9 @@
     /** File header magic number: "ANET" */
     private static final int FILE_MAGIC = 0x414E4554;
 
+    /** Default buffer size from BufferedInputStream */
+    private static final int BUFFER_SIZE = 8192;
+
     private static final int VERSION_NETWORK_INIT = 1;
 
     private static final int VERSION_UID_INIT = 1;
@@ -434,7 +439,8 @@
 
     @Override
     public void read(InputStream in) throws IOException {
-        read((DataInput) new DataInputStream(in));
+        final FastDataInput dataIn = new FastDataInput(in, BUFFER_SIZE);
+        read(dataIn);
     }
 
     private void read(DataInput in) throws IOException {
@@ -473,8 +479,9 @@
 
     @Override
     public void write(OutputStream out) throws IOException {
-        write((DataOutput) new DataOutputStream(out));
-        out.flush();
+        final FastDataOutput dataOut = new FastDataOutput(out, BUFFER_SIZE);
+        write(dataOut);
+        dataOut.flush();
     }
 
     private void write(DataOutput out) throws IOException {
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 9706bce..ebf1fe9 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -97,7 +97,7 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkIdentity;
 import android.net.NetworkStack;
-import android.net.NetworkState;
+import android.net.NetworkStateSnapshot;
 import android.net.NetworkStats;
 import android.net.NetworkStats.NonMonotonicObserver;
 import android.net.NetworkStatsHistory;
@@ -296,7 +296,7 @@
     /** Last states of all networks sent from ConnectivityService. */
     @GuardedBy("mStatsLock")
     @Nullable
-    private NetworkState[] mLastNetworkStates = null;
+    private NetworkStateSnapshot[] mLastNetworkStateSnapshots = null;
 
     private final DropBoxNonMonotonicObserver mNonMonotonicObserver =
             new DropBoxNonMonotonicObserver();
@@ -378,8 +378,9 @@
                 }
                 case MSG_UPDATE_IFACES: {
                     // If no cached states, ignore.
-                    if (mLastNetworkStates == null) break;
-                    updateIfaces(mDefaultNetworks, mLastNetworkStates, mActiveIface);
+                    if (mLastNetworkStateSnapshots == null) break;
+                    // TODO (b/181642673): Protect mDefaultNetworks from concurrent accessing.
+                    updateIfaces(mDefaultNetworks, mLastNetworkStateSnapshots, mActiveIface);
                     break;
                 }
                 case MSG_PERFORM_POLL_REGISTER_ALERT: {
@@ -967,10 +968,9 @@
         }
     }
 
-    @Override
     public void forceUpdateIfaces(
             Network[] defaultNetworks,
-            NetworkState[] networkStates,
+            NetworkStateSnapshot[] networkStates,
             String activeIface,
             UnderlyingNetworkInfo[] underlyingNetworkInfos) {
         checkNetworkStackPermission(mContext);
@@ -1248,13 +1248,13 @@
 
     private void updateIfaces(
             Network[] defaultNetworks,
-            NetworkState[] networkStates,
+            NetworkStateSnapshot[] snapshots,
             String activeIface) {
         synchronized (mStatsLock) {
             mWakeLock.acquire();
             try {
                 mActiveIface = activeIface;
-                updateIfacesLocked(defaultNetworks, networkStates);
+                updateIfacesLocked(defaultNetworks, snapshots);
             } finally {
                 mWakeLock.release();
             }
@@ -1262,13 +1262,13 @@
     }
 
     /**
-     * Inspect all current {@link NetworkState} to derive mapping from {@code iface} to {@link
-     * NetworkStatsHistory}. When multiple networks are active on a single {@code iface},
+     * Inspect all current {@link NetworkStateSnapshot}s to derive mapping from {@code iface} to
+     * {@link NetworkStatsHistory}. When multiple networks are active on a single {@code iface},
      * they are combined under a single {@link NetworkIdentitySet}.
      */
     @GuardedBy("mStatsLock")
-    private void updateIfacesLocked(@Nullable Network[] defaultNetworks,
-            @NonNull NetworkState[] states) {
+    private void updateIfacesLocked(@NonNull Network[] defaultNetworks,
+            @NonNull NetworkStateSnapshot[] snapshots) {
         if (!mSystemReady) return;
         if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
 
@@ -1283,26 +1283,24 @@
         // Rebuild active interfaces based on connected networks
         mActiveIfaces.clear();
         mActiveUidIfaces.clear();
-        if (defaultNetworks != null) {
-            // Caller is ConnectivityService. Update the list of default networks.
-            mDefaultNetworks = defaultNetworks;
-        }
+        // Update the list of default networks.
+        mDefaultNetworks = defaultNetworks;
 
-        mLastNetworkStates = states;
+        mLastNetworkStateSnapshots = snapshots;
 
         final boolean combineSubtypeEnabled = mSettings.getCombineSubtypeEnabled();
         final ArraySet<String> mobileIfaces = new ArraySet<>();
-        for (NetworkState state : states) {
-            final boolean isMobile = isNetworkTypeMobile(state.legacyNetworkType);
-            final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, state.network);
+        for (NetworkStateSnapshot snapshot : snapshots) {
+            final boolean isMobile = isNetworkTypeMobile(snapshot.legacyType);
+            final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, snapshot.network);
             final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED
-                    : getSubTypeForState(state);
-            final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state,
+                    : getSubTypeForStateSnapshot(snapshot);
+            final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot,
                     isDefault, subType);
 
             // Traffic occurring on the base interface is always counted for
             // both total usage and UID details.
-            final String baseIface = state.linkProperties.getInterfaceName();
+            final String baseIface = snapshot.linkProperties.getInterfaceName();
             if (baseIface != null) {
                 findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident);
                 findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident);
@@ -1312,14 +1310,14 @@
                 // If IMS is metered, then the IMS network usage has already included VT usage.
                 // VT is considered always metered in framework's layer. If VT is not metered
                 // per carrier's policy, modem will report 0 usage for VT calls.
-                if (state.networkCapabilities.hasCapability(
+                if (snapshot.networkCapabilities.hasCapability(
                         NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.getMetered()) {
 
                     // Copy the identify from IMS one but mark it as metered.
                     NetworkIdentity vtIdent = new NetworkIdentity(ident.getType(),
                             ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(),
                             ident.getRoaming(), true /* metered */,
-                            true /* onDefaultNetwork */);
+                            true /* onDefaultNetwork */, ident.getOemManaged());
                     findOrCreateNetworkIdentitySet(mActiveIfaces, IFACE_VT).add(vtIdent);
                     findOrCreateNetworkIdentitySet(mActiveUidIfaces, IFACE_VT).add(vtIdent);
                 }
@@ -1358,7 +1356,7 @@
             // (or non eBPF offloaded) TX they would appear on both, however egress interface
             // accounting is explicitly bypassed for traffic from the clat uid.
             //
-            final List<LinkProperties> stackedLinks = state.linkProperties.getStackedLinks();
+            final List<LinkProperties> stackedLinks = snapshot.linkProperties.getStackedLinks();
             for (LinkProperties stackedLink : stackedLinks) {
                 final String stackedIface = stackedLink.getInterfaceName();
                 if (stackedIface != null) {
@@ -1381,7 +1379,7 @@
      * {@link PhoneStateListener}. Otherwise, return 0 given that other networks with different
      * transport types do not actually fill this value.
      */
-    private int getSubTypeForState(@NonNull NetworkState state) {
+    private int getSubTypeForStateSnapshot(@NonNull NetworkStateSnapshot state) {
         if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
             return 0;
         }
diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java
index 160d2da..afb47e8 100644
--- a/services/core/java/com/android/server/notification/NotificationDelegate.java
+++ b/services/core/java/com/android/server/notification/NotificationDelegate.java
@@ -32,7 +32,7 @@
     void onNotificationActionClick(int callingUid, int callingPid, String key, int actionIndex,
             Notification.Action action, NotificationVisibility nv, boolean generatedByAssistant);
     void onNotificationClear(int callingUid, int callingPid,
-            String pkg, String tag, int id, int userId, String key,
+            String pkg, int userId, String key,
             @NotificationStats.DismissalSurface int dismissalSurface,
             @NotificationStats.DismissalSentiment int dismissalSentiment,
             NotificationVisibility nv);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 8b4c639..73db705 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -64,6 +64,8 @@
 import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
+import static android.os.PowerWhitelistManager.REASON_NOTIFICATION_SERVICE;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
 import static android.os.UserHandle.USER_NULL;
 import static android.os.UserHandle.USER_SYSTEM;
 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
@@ -73,6 +75,8 @@
 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
+import static android.service.notification.NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES;
+import static android.service.notification.NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES;
 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
@@ -1044,15 +1048,19 @@
 
         @Override
         public void onNotificationClear(int callingUid, int callingPid,
-                String pkg, String tag, int id, int userId, String key,
+                String pkg, int userId, String key,
                 @NotificationStats.DismissalSurface int dismissalSurface,
                 @NotificationStats.DismissalSentiment int dismissalSentiment,
                 NotificationVisibility nv) {
+            String tag = null;
+            int id = 0;
             synchronized (mNotificationLock) {
                 NotificationRecord r = mNotificationsByKey.get(key);
                 if (r != null) {
                     r.recordDismissalSurface(dismissalSurface);
                     r.recordDismissalSentiment(dismissalSentiment);
+                    tag = r.getSbn().getTag();
+                    id = r.getSbn().getId();
                 }
             }
             cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
@@ -5997,10 +6005,11 @@
                 for (int i = 0; i < intentCount; i++) {
                     PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
                     if (pendingIntent != null) {
-                        am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
+                        am.setPendingIntentAllowlistDuration(pendingIntent.getTarget(),
                                 ALLOWLIST_TOKEN, duration,
-                                BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED
-                        );
+                                TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                                REASON_NOTIFICATION_SERVICE,
+                                "NotificationManagerService");
                         am.setPendingIntentAllowBgActivityStarts(pendingIntent.getTarget(),
                                 ALLOWLIST_TOKEN, (FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER
                                         | FLAG_SERVICE_SENDER));
@@ -9859,33 +9868,54 @@
             Pair listener = Pair.create(si.getComponentName(), userId);
             NotificationListenerFilter existingNlf =
                     mRequestedNotificationListeners.get(listener);
-            if (existingNlf  == null) {
-                // no stored filters for this listener; see if they provided a default
-                if (si.metaData != null) {
-                    String typeList = si.metaData.getString(
-                            NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES);
-                    if (typeList != null) {
-                        int types = 0;
-                        String[] typeStrings = typeList.split(XML_SEPARATOR);
-                        for (int i = 0; i < typeStrings.length; i++) {
-                            if (TextUtils.isEmpty(typeStrings[i])) {
-                                continue;
-                            }
-                            try {
-                                types |= Integer.parseInt(typeStrings[i]);
-                            } catch (NumberFormatException e) {
-                                // skip
-                            }
+            if (si.metaData != null) {
+                if (existingNlf  == null) {
+                    // no stored filters for this listener; see if they provided a default
+                    if (si.metaData.containsKey(META_DATA_DEFAULT_FILTER_TYPES)) {
+                        String typeList =
+                                si.metaData.get(META_DATA_DEFAULT_FILTER_TYPES).toString();
+                        if (typeList != null) {
+                            int types = getTypesFromStringList(typeList);
+                            NotificationListenerFilter nlf =
+                                    new NotificationListenerFilter(types, new ArraySet<>());
+                            mRequestedNotificationListeners.put(listener, nlf);
                         }
+                    }
+                }
 
-                         NotificationListenerFilter nlf =
-                                 new NotificationListenerFilter(types, new ArraySet<>());
+                // also check the types they never want bridged
+                if (si.metaData.containsKey(META_DATA_DISABLED_FILTER_TYPES)) {
+                    int neverBridge = getTypesFromStringList(si.metaData.get(
+                            META_DATA_DISABLED_FILTER_TYPES).toString());
+                    if (neverBridge != 0) {
+                        NotificationListenerFilter nlf =
+                                mRequestedNotificationListeners.getOrDefault(
+                                        listener, new NotificationListenerFilter());
+                        nlf.setTypes(nlf.getTypes() & ~neverBridge);
                         mRequestedNotificationListeners.put(listener, nlf);
                     }
                 }
             }
         }
 
+        private int getTypesFromStringList(String typeList) {
+            int types = 0;
+            if (typeList != null) {
+                String[] typeStrings = typeList.split(XML_SEPARATOR);
+                for (int i = 0; i < typeStrings.length; i++) {
+                    if (TextUtils.isEmpty(typeStrings[i])) {
+                        continue;
+                    }
+                    try {
+                        types |= Integer.parseInt(typeStrings[i]);
+                    } catch (NumberFormatException e) {
+                        // skip
+                    }
+                }
+            }
+            return types;
+        }
+
         @GuardedBy("mNotificationLock")
         public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
             if (trim == TRIM_LIGHT) {
diff --git a/services/core/java/com/android/server/pm/DataLoaderManagerService.java b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
index 308e815..b34611b 100644
--- a/services/core/java/com/android/server/pm/DataLoaderManagerService.java
+++ b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
@@ -171,7 +171,7 @@
         }
     }
 
-    private class DataLoaderServiceConnection implements ServiceConnection {
+    private class DataLoaderServiceConnection implements ServiceConnection, IBinder.DeathRecipient {
         final int mId;
         final IDataLoaderStatusListener mListener;
         IDataLoader mDataLoader;
@@ -194,34 +194,50 @@
                 mContext.unbindService(this);
                 return;
             }
+            try {
+                service.linkToDeath(this, /*flags=*/0);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to link to DataLoader's death: " + mId, e);
+                onBindingDied(className);
+                return;
+            }
             callListener(IDataLoaderStatusListener.DATA_LOADER_BOUND);
         }
 
         @Override
         public void onServiceDisconnected(ComponentName arg0) {
             Slog.i(TAG, "DataLoader " + mId + " disconnected, but will try to recover");
-            callListener(IDataLoaderStatusListener.DATA_LOADER_DESTROYED);
-            destroy();
+            unbindAndReportDestroyed();
         }
 
         @Override
         public void onBindingDied(ComponentName name) {
             Slog.i(TAG, "DataLoader " + mId + " died");
-            callListener(IDataLoaderStatusListener.DATA_LOADER_DESTROYED);
-            destroy();
+            unbindAndReportDestroyed();
         }
 
         @Override
         public void onNullBinding(ComponentName name) {
             Slog.i(TAG, "DataLoader " + mId + " failed to start");
-            callListener(IDataLoaderStatusListener.DATA_LOADER_DESTROYED);
-            destroy();
+            unbindAndReportDestroyed();
+        }
+
+        @Override
+        public void binderDied() {
+            Slog.i(TAG, "DataLoader " + mId + " died");
+            unbindAndReportDestroyed();
         }
 
         IDataLoader getDataLoader() {
             return mDataLoader;
         }
 
+        private void unbindAndReportDestroyed() {
+            if (unbind()) {
+                callListener(IDataLoaderStatusListener.DATA_LOADER_DESTROYED);
+            }
+        }
+
         void destroy() {
             if (mDataLoader != null) {
                 try {
@@ -230,11 +246,15 @@
                 }
                 mDataLoader = null;
             }
+            unbind();
+        }
+
+        boolean unbind() {
             try {
                 mContext.unbindService(this);
             } catch (Exception ignored) {
             }
-            remove();
+            return remove();
         }
 
         private boolean append() {
@@ -252,12 +272,14 @@
             }
         }
 
-        private void remove() {
+        private boolean remove() {
             synchronized (mServiceConnections) {
                 if (mServiceConnections.get(mId) == this) {
                     mServiceConnections.remove(mId);
+                    return true;
                 }
             }
+            return false;
         }
 
         private void callListener(int status) {
diff --git a/services/core/java/com/android/server/pm/DumpState.java b/services/core/java/com/android/server/pm/DumpState.java
index 380cdb1..6875b8a 100644
--- a/services/core/java/com/android/server/pm/DumpState.java
+++ b/services/core/java/com/android/server/pm/DumpState.java
@@ -56,6 +56,7 @@
 
     private boolean mTitlePrinted;
     private boolean mFullPreferred;
+    private boolean mCheckIn;
 
     private String mTargetPackageName;
 
@@ -118,4 +119,12 @@
     public void setFullPreferred(boolean fullPreferred) {
         mFullPreferred = fullPreferred;
     }
+
+    public boolean isCheckIn() {
+        return mCheckIn;
+    }
+
+    public void setCheckIn(boolean checkIn) {
+        mCheckIn = checkIn;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 2812830..a5e28f1 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -530,14 +530,6 @@
             throw new SecurityException("User restriction prevents installing");
         }
 
-        if (params.dataLoaderParams != null
-                && mContext.checkCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2)
-                        != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("You need the "
-                    + "com.android.permission.USE_INSTALLER_V2 permission "
-                    + "to use a data loader");
-        }
-
         // INSTALL_REASON_ROLLBACK allows an app to be rolled back without requiring the ROLLBACK
         // capability; ensure if this is set as the install reason the app has one of the necessary
         // signature permissions to perform the rollback.
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 7bf3c5c..460b2f2 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -3547,14 +3547,12 @@
 
     @Override
     public DataLoaderParamsParcel getDataLoaderParams() {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null);
         return params.dataLoaderParams != null ? params.dataLoaderParams.getData() : null;
     }
 
     @Override
     public void addFile(int location, String name, long lengthBytes, byte[] metadata,
             byte[] signature) {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null);
         if (!isDataLoaderInstallation()) {
             throw new IllegalStateException(
                     "Cannot add files to non-data loader installation session.");
@@ -3587,7 +3585,6 @@
 
     @Override
     public void removeFile(int location, String name) {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null);
         if (!isDataLoaderInstallation()) {
             throw new IllegalStateException(
                     "Cannot add files to non-data loader installation session.");
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 16966d4..7da53b5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -97,6 +97,10 @@
 import static android.content.pm.PackageManagerInternal.LAST_KNOWN_PACKAGE;
 import static android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4;
 import static android.content.pm.parsing.ApkLiteParseUtils.isApkFile;
+import static android.os.PowerWhitelistManager.REASON_LOCKED_BOOT_COMPLETED;
+import static android.os.PowerWhitelistManager.REASON_PACKAGE_REPLACED;
+import static android.os.PowerWhitelistManager.REASON_PACKAGE_VERIFIER;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 import static android.os.incremental.IncrementalManager.isIncrementalPath;
 import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
@@ -270,6 +274,7 @@
 import android.os.ParcelableException;
 import android.os.PatternMatcher;
 import android.os.PersistableBundle;
+import android.os.PowerWhitelistManager;
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -1961,9 +1966,10 @@
         boolean isInstantAppInternal(String packageName, @UserIdInt int userId, int callingUid);
         boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId, int callingUid);
         boolean isInstantAppResolutionAllowed(Intent intent, List<ResolveInfo> resolvedActivities,
-                int userId, boolean skipPackageCheck);
+                int userId, boolean skipPackageCheck, int flags);
         boolean isInstantAppResolutionAllowedBody(Intent intent,
-                List<ResolveInfo> resolvedActivities, int userId, boolean skipPackageCheck);
+                List<ResolveInfo> resolvedActivities, int userId, boolean skipPackageCheck,
+                int flags);
         boolean isPersistentPreferredActivitySetByDpm(Intent intent, int userId,
                 String resolvedType, int flags);
         boolean isRecentsAccessingChildProfiles(int callingUid, int targetUserId);
@@ -2322,7 +2328,7 @@
                 result = filterIfNotSystemUser(mComponentResolver.queryActivities(
                         intent, resolvedType, flags, userId), userId);
                 addInstant = isInstantAppResolutionAllowed(intent, result, userId,
-                        false /*skipPackageCheck*/);
+                        false /*skipPackageCheck*/, flags);
                 // Check for cross profile results.
                 boolean hasNonNegativePriorityResult = hasNonNegativePriority(result);
                 xpResolveInfo = queryCrossProfileIntents(
@@ -2387,8 +2393,8 @@
                 if (result == null || result.size() == 0) {
                     // the caller wants to resolve for a particular package; however, there
                     // were no installed results, so, try to find an ephemeral result
-                    addInstant = isInstantAppResolutionAllowed(
-                                    intent, null /*result*/, userId, true /*skipPackageCheck*/);
+                    addInstant = isInstantAppResolutionAllowed(intent, null /*result*/, userId,
+                            true /*skipPackageCheck*/, flags);
                     if (result == null) {
                         result = new ArrayList<>();
                     }
@@ -2603,10 +2609,22 @@
             final ArrayList<ResolveInfo> matchAllList = new ArrayList<>();
             final ArrayList<ResolveInfo> undefinedList = new ArrayList<>();
 
+            // Blocking instant apps is usually done in applyPostResolutionFilter, but since
+            // domain verification can resolve to a single result, which can be an instant app,
+            // it will then be filtered to an empty list in that method. Instead, do blocking
+            // here so that instant apps can be ignored for approval filtering and a lower
+            // priority result chosen instead.
+            final boolean blockInstant = intent.isWebIntent() && areWebInstantAppsDisabled(userId);
+
             final int count = candidates.size();
             // First, try to use approved apps.
             for (int n = 0; n < count; n++) {
                 ResolveInfo info = candidates.get(n);
+                if (blockInstant && (info.isInstantAppAvailable
+                        || isInstantApp(info.activityInfo.packageName, userId))) {
+                    continue;
+                }
+
                 // Add to the special match all list (Browser use case)
                 if (info.handleAllWebDataURI) {
                     matchAllList.add(info);
@@ -2618,7 +2636,8 @@
             // We'll want to include browser possibilities in a few cases
             boolean includeBrowser = false;
 
-            if (!DomainVerificationUtils.isDomainVerificationIntent(intent)) {
+            if (!DomainVerificationUtils.isDomainVerificationIntent(intent, candidates,
+                            matchFlags)) {
                 result.addAll(undefinedList);
                 // Maybe add one for the other profile.
                 if (xpDomainInfo != null && xpDomainInfo.highestApprovalLevel
@@ -2802,8 +2821,8 @@
                 }
 
                 result.highestApprovalLevel = Math.max(mDomainVerificationManager
-                        .approvalLevelForDomain(ps, intent, riTargetUser.targetUserId),
-                        result.highestApprovalLevel);
+                        .approvalLevelForDomain(ps, intent, resultTargetUser, flags,
+                                riTargetUser.targetUserId), result.highestApprovalLevel);
             }
             if (result != null && result.highestApprovalLevel
                     <= DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE) {
@@ -3050,7 +3069,7 @@
                     final PackageSetting ps = mSettings.getPackageLPr(packageName);
                     if (ps.getInstantApp(userId)) {
                         if (hasAnyDomainApproval(mDomainVerificationManager, ps, intent,
-                                userId)) {
+                                instantApps, flags, userId)) {
                             if (DEBUG_INSTANT) {
                                 Slog.v(TAG, "Instant app approved for intent; pkg: "
                                         + packageName);
@@ -3928,7 +3947,7 @@
 
         public boolean isInstantAppResolutionAllowed(
                 Intent intent, List<ResolveInfo> resolvedActivities, int userId,
-                boolean skipPackageCheck) {
+                boolean skipPackageCheck, int flags) {
             if (mInstantAppResolverConnection == null) {
                 return false;
             }
@@ -3961,14 +3980,14 @@
             // Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
             // Or if there's already an ephemeral app installed that handles the action
             return isInstantAppResolutionAllowedBody(intent, resolvedActivities, userId,
-                                                       skipPackageCheck);
+                                                       skipPackageCheck, flags);
         }
 
         // Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
         // Or if there's already an ephemeral app installed that handles the action
         public boolean isInstantAppResolutionAllowedBody(
                 Intent intent, List<ResolveInfo> resolvedActivities, int userId,
-                boolean skipPackageCheck) {
+                boolean skipPackageCheck, int flags) {
             final int count = (resolvedActivities == null ? 0 : resolvedActivities.size());
             for (int n = 0; n < count; n++) {
                 final ResolveInfo info = resolvedActivities.get(n);
@@ -3978,7 +3997,7 @@
                     // only check domain verification status if the app is not a browser
                     if (!info.handleAllWebDataURI) {
                         if (hasAnyDomainApproval(mDomainVerificationManager, ps, intent,
-                                userId)) {
+                                resolvedActivities, flags, userId)) {
                             if (DEBUG_INSTANT) {
                                 Slog.v(TAG, "DENY instant app;" + " pkg: " + packageName
                                         + ", approved");
@@ -4403,6 +4422,7 @@
 
         public void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
             final String packageName = dumpState.getTargetPackageName();
+            final boolean checkin = dumpState.isCheckIn();
 
             switch (type) {
                 case DumpState.DUMP_VERSION:
@@ -4415,6 +4435,56 @@
                     break;
                 }
 
+                case DumpState.DUMP_LIBS:
+                {
+                    boolean printedHeader = false;
+                    final int numSharedLibraries = mSharedLibraries.size();
+                    for (int index = 0; index < numSharedLibraries; index++) {
+                        final String libName = mSharedLibraries.keyAt(index);
+                        final WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
+                                mSharedLibraries.get(libName);
+                        if (versionedLib == null) {
+                            continue;
+                        }
+                        final int versionCount = versionedLib.size();
+                        for (int i = 0; i < versionCount; i++) {
+                            SharedLibraryInfo libraryInfo = versionedLib.valueAt(i);
+                            if (!checkin) {
+                                if (!printedHeader) {
+                                    if (dumpState.onTitlePrinted()) {
+                                        pw.println();
+                                    }
+                                    pw.println("Libraries:");
+                                    printedHeader = true;
+                                }
+                                pw.print("  ");
+                            } else {
+                                pw.print("lib,");
+                            }
+                            pw.print(libraryInfo.getName());
+                            if (libraryInfo.isStatic()) {
+                                pw.print(" version=" + libraryInfo.getLongVersion());
+                            }
+                            if (!checkin) {
+                                pw.print(" -> ");
+                            }
+                            if (libraryInfo.getPath() != null) {
+                                if (libraryInfo.isNative()) {
+                                    pw.print(" (so) ");
+                                } else {
+                                    pw.print(" (jar) ");
+                                }
+                                pw.print(libraryInfo.getPath());
+                            } else {
+                                pw.print(" (apk) ");
+                                pw.print(libraryInfo.getPackageName());
+                            }
+                            pw.println();
+                        }
+                    }
+                    break;
+                }
+
                 case DumpState.DUMP_PREFERRED_XML:
                 {
                     pw.flush();
@@ -4565,7 +4635,7 @@
      * computer engine.  This is required because there are no locks taken in
      * the engine itself.
      */
-    private static class ComputerLocked extends ComputerEngine {
+    private static class ComputerLocked extends ComputerEngineLive {
         private final Object mLock;
 
         ComputerLocked(Snapshot args) {
@@ -4573,16 +4643,6 @@
             mLock = mService.mLock;
         }
 
-        protected ComponentName resolveComponentName() {
-            return mService.mResolveComponentName;
-        }
-        protected ActivityInfo instantAppInstallerActivity() {
-            return mService.mInstantAppInstallerActivity;
-        }
-        protected ApplicationInfo androidApplication() {
-            return mService.mAndroidApplication;
-        }
-
         public @NonNull List<ResolveInfo> queryIntentServicesInternalBody(Intent intent,
                 String resolvedType, int flags, int userId, int callingUid,
                 String instantAppPkgName) {
@@ -4676,10 +4736,11 @@
             }
         }
         public boolean isInstantAppResolutionAllowedBody(Intent intent,
-                List<ResolveInfo> resolvedActivities, int userId, boolean skipPackageCheck) {
+                List<ResolveInfo> resolvedActivities, int userId, boolean skipPackageCheck,
+                int flags) {
             synchronized (mLock) {
                 return super.isInstantAppResolutionAllowedBody(intent, resolvedActivities, userId,
-                        skipPackageCheck);
+                        skipPackageCheck, flags);
             }
         }
         public int getPackageUidInternal(String packageName, int flags, int userId,
@@ -4711,8 +4772,9 @@
     }
 
 
-    // Compute read-only functions, based on live data.
-    private final Computer mLiveComputer;
+    // Compute read-only functions, based on live data.  This attribute may be modified multiple
+    // times during the PackageManagerService constructor but it should not be modified thereafter.
+    private Computer mLiveComputer;
     // A lock-free cache for frequently called functions.
     private volatile Computer mSnapshotComputer;
     // If true, the snapshot is invalid (stale).  The attribute is static since it may be
@@ -5039,23 +5101,12 @@
                         InstallArgs args = data.args;
                         PackageInstalledInfo parentRes = data.res;
 
-                        final boolean grantPermissions = (args.installFlags
-                                & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
                         final boolean killApp = (args.installFlags
                                 & PackageManager.INSTALL_DONT_KILL_APP) == 0;
                         final boolean virtualPreload = ((args.installFlags
                                 & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
-                        final String[] grantedPermissions = args.installGrantPermissions;
-                        final List<String> whitelistedRestrictedPermissions = ((args.installFlags
-                                & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0
-                                    && parentRes.pkg != null)
-                                ? parentRes.pkg.getRequestedPermissions()
-                                : args.whitelistedRestrictedPermissions;
-                        int autoRevokePermissionsMode = args.autoRevokePermissionsMode;
 
-                        handlePackagePostInstall(parentRes, grantPermissions,
-                                killApp, virtualPreload, grantedPermissions,
-                                whitelistedRestrictedPermissions, autoRevokePermissionsMode,
+                        handlePackagePostInstall(parentRes, killApp, virtualPreload,
                                 didRestore, args.installSource.installerPackageName, args.observer,
                                 args.mDataLoaderType);
 
@@ -5334,11 +5385,8 @@
         }
     }
 
-    private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
-            boolean killApp, boolean virtualPreload,
-            String[] grantedPermissions, List<String> allowlistedRestrictedPermissions,
-            int autoRevokePermissionsMode,
-            boolean launchedForRestore, String installerPackage,
+    private void handlePackagePostInstall(PackageInstalledInfo res, boolean killApp,
+            boolean virtualPreload, boolean launchedForRestore, String installerPackage,
             IPackageInstallObserver2 installObserver, int dataLoaderType) {
         boolean succeeded = res.returnCode == PackageManager.INSTALL_SUCCEEDED;
         final boolean update = res.removedInfo != null && res.removedInfo.removedPackage != null;
@@ -5369,29 +5417,6 @@
                 res.removedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/);
             }
 
-            final PermissionManagerServiceInternal.PackageInstalledParams.Builder
-                    permissionParamsBuilder =
-                    new PermissionManagerServiceInternal.PackageInstalledParams.Builder();
-            final List<String> grantedPermissionsList;
-            if (grantPermissions) {
-                if (grantedPermissions != null) {
-                    permissionParamsBuilder.setGrantedPermissions(Arrays.asList(
-                            grantedPermissions));
-                } else {
-                    permissionParamsBuilder.setGrantedPermissions(
-                            res.pkg.getRequestedPermissions());
-                }
-            }
-            if (allowlistedRestrictedPermissions != null) {
-                permissionParamsBuilder.setAllowlistedRestrictedPermissions(
-                        allowlistedRestrictedPermissions);
-            }
-            permissionParamsBuilder.setAutoRevokePermissionsMode(autoRevokePermissionsMode);
-            for (final int userId : res.newUsers) {
-                mPermissionManager.onPackageInstalled(res.pkg, permissionParamsBuilder.build(),
-                        userId);
-            }
-
             final String installerPackageName =
                     res.installerPackageName != null
                             ? res.installerPackageName
@@ -5524,7 +5549,8 @@
                             packageName /*targetPackage*/,
                             null /*finishedReceiver*/, updateUserIds, instantUserIds,
                             null /*broadcastAllowList*/,
-                            getTemporaryAppWhitelistBroadcastOptions().toBundle());
+                            getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED)
+                                    .toBundle());
                 } else if (launchedForRestore && !res.pkg.isSystem()) {
                     // First-install and we did a restore, so we're responsible for the
                     // first-launch broadcast.
@@ -6367,8 +6393,9 @@
         // constructor.
         mSnapshotEnabled = SNAPSHOT_ENABLED;
         sSnapshotCorked = true;
+        sSnapshotInvalid = true;
         mLiveComputer = createLiveComputer();
-        mSnapshotComputer = mLiveComputer;
+        mSnapshotComputer = null;
         registerObserver();
 
         // CHECKSTYLE:OFF IndentationCheck
@@ -7047,6 +7074,10 @@
                         BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME,
                         SystemClock.uptimeMillis() - startTime);
             }
+
+            // Rebild the live computer since some attributes have been rebuilt.
+            mLiveComputer = createLiveComputer();
+
         } // synchronized (mLock)
         } // synchronized (mInstallLock)
         // CHECKSTYLE:ON IndentationCheck
@@ -9167,6 +9198,11 @@
      */
     @Override
     public String[] getPackagesForUid(int uid) {
+        final int callingUid = Binder.getCallingUid();
+        final int userId = UserHandle.getUserId(uid);
+        enforceCrossUserOrProfilePermission(callingUid, userId,
+                /* requireFullPermission */ false,
+                /* checkShell */ false, "getPackagesForUid");
         return snapshotComputer().getPackagesForUid(uid);
     }
 
@@ -9470,20 +9506,20 @@
 
     private boolean isInstantAppResolutionAllowed(
             Intent intent, List<ResolveInfo> resolvedActivities, int userId,
-            boolean skipPackageCheck) {
+            boolean skipPackageCheck, int flags) {
         return liveComputer().isInstantAppResolutionAllowed(
             intent, resolvedActivities, userId,
-            skipPackageCheck);
+            skipPackageCheck, flags);
     }
 
     // Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
     // Or if there's already an ephemeral app installed that handles the action
     private boolean isInstantAppResolutionAllowedBody(
             Intent intent, List<ResolveInfo> resolvedActivities, int userId,
-            boolean skipPackageCheck) {
+            boolean skipPackageCheck, int flags) {
         return liveComputer().isInstantAppResolutionAllowedBody(
             intent, resolvedActivities, userId,
-            skipPackageCheck);
+            skipPackageCheck, flags);
     }
 
     private void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
@@ -9540,7 +9576,7 @@
                         final String packageName = ri.activityInfo.packageName;
                         final PackageSetting ps = mSettings.getPackageLPr(packageName);
                         if (ps != null && hasAnyDomainApproval(mDomainVerificationManager, ps,
-                                intent, userId)) {
+                                intent, query, flags, userId)) {
                             return ri;
                         }
                     }
@@ -9597,9 +9633,10 @@
      */
     private static boolean hasAnyDomainApproval(
             @NonNull DomainVerificationManagerInternal manager, @NonNull PackageSetting pkgSetting,
-            @NonNull Intent intent, @UserIdInt int userId) {
-        return manager.approvalLevelForDomain(pkgSetting, intent, userId)
-                > DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE;
+            @NonNull Intent intent, @NonNull List<ResolveInfo> candidates,
+            @PackageManager.ResolveInfoFlags int resolveInfoFlags, @UserIdInt int userId) {
+        return manager.approvalLevelForDomain(pkgSetting, intent, candidates, resolveInfoFlags,
+                userId) > DomainVerificationManagerInternal.APPROVAL_LEVEL_NONE;
     }
 
     /**
@@ -11597,9 +11634,17 @@
                 healthCheckParams.unhealthyTimeoutMs = INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS;
                 healthCheckParams.unhealthyMonitoringMs =
                         INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS;
+                // Continue monitoring health and loading progress of active incremental packages
                 mIncrementalManager.registerHealthListener(parsedPackage.getPath(),
                         healthCheckParams,
                         new IncrementalHealthListener(parsedPackage.getPackageName()));
+                final IncrementalStatesCallback incrementalStatesCallback =
+                        new IncrementalStatesCallback(parsedPackage.getPackageName(),
+                                UserHandle.getUid(UserHandle.ALL, pkgSetting.appId),
+                                getInstalledUsers(pkgSetting, UserHandle.USER_ALL));
+                pkgSetting.setIncrementalStatesCallback(incrementalStatesCallback);
+                mIncrementalManager.registerLoadingProgressCallback(parsedPackage.getPath(),
+                        new IncrementalProgressListener(parsedPackage.getPackageName()));
             }
         }
         return scanResult.pkgSetting.pkg;
@@ -15159,7 +15204,8 @@
                 lockedBcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
             }
             final String[] requiredPermissions = {Manifest.permission.RECEIVE_BOOT_COMPLETED};
-            final BroadcastOptions bOptions = getTemporaryAppWhitelistBroadcastOptions();
+            final BroadcastOptions bOptions = getTemporaryAppAllowlistBroadcastOptions(
+                    REASON_LOCKED_BOOT_COMPLETED);
             am.broadcastIntentWithFeature(null, null, lockedBcIntent, null, null, 0, null, null,
                     requiredPermissions, android.app.AppOpsManager.OP_NONE, bOptions.toBundle(),
                     false, false,
@@ -17548,7 +17594,9 @@
                         mInjector.getLocalService(DeviceIdleInternal.class);
                 final long idleDuration = getVerificationTimeout();
                 final BroadcastOptions options = BroadcastOptions.makeBasic();
-                options.setTemporaryAppWhitelistDuration(idleDuration);
+                options.setTemporaryAppAllowlist(idleDuration,
+                        TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                        REASON_PACKAGE_VERIFIER, "");
 
                 /*
                  * If any sufficient verifiers were listed in the package
@@ -17564,7 +17612,8 @@
                             final ComponentName verifierComponent = sufficientVerifiers.get(i);
                             idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
                                     verifierComponent.getPackageName(), idleDuration,
-                                    verifierUser.getIdentifier(), false, "package verifier");
+                                    verifierUser.getIdentifier(), false,
+                                    REASON_PACKAGE_VERIFIER,"package verifier");
 
                             final Intent sufficientIntent = new Intent(verification);
                             sufficientIntent.setComponent(verifierComponent);
@@ -17586,7 +17635,8 @@
                     verification.setComponent(requiredVerifierComponent);
                     idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
                             mRequiredVerifierPackage, idleDuration,
-                            verifierUser.getIdentifier(), false, "package verifier");
+                            verifierUser.getIdentifier(), false,
+                            REASON_PACKAGE_VERIFIER, "package verifier");
                     mContext.sendOrderedBroadcastAsUser(verification, verifierUser,
                             android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
                             /* appOp= */ AppOpsManager.OP_NONE,
@@ -17943,7 +17993,9 @@
             try {
                 makeDirRecursive(afterCodeFile.getParentFile(), 0775);
                 if (onIncremental) {
-                    mIncrementalManager.renameCodePath(beforeCodeFile, afterCodeFile);
+                    // Just link files here. The stage dir will be removed when the installation
+                    // session is completed.
+                    mIncrementalManager.linkCodePath(beforeCodeFile, afterCodeFile);
                 } else {
                     Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());
                 }
@@ -17952,7 +18004,6 @@
                 return false;
             }
 
-            //TODO(b/136132412): enable selinux restorecon for incremental directories
             if (!onIncremental && !SELinux.restoreconRecursive(afterCodeFile)) {
                 Slog.w(TAG, "Failed to restorecon");
                 return false;
@@ -18386,6 +18437,37 @@
                 }
 
                 mSettings.writeKernelMappingLPr(ps);
+
+                final PermissionManagerServiceInternal.PackageInstalledParams.Builder
+                        permissionParamsBuilder =
+                        new PermissionManagerServiceInternal.PackageInstalledParams.Builder();
+                final boolean grantPermissions = (installArgs.installFlags
+                        & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
+                if (grantPermissions) {
+                    final List<String> grantedPermissions =
+                            installArgs.installGrantPermissions != null
+                                    ? Arrays.asList(installArgs.installGrantPermissions)
+                                    : pkg.getRequestedPermissions();
+                    permissionParamsBuilder.setGrantedPermissions(grantedPermissions);
+                }
+                final boolean allowlistAllRestrictedPermissions =
+                        (installArgs.installFlags
+                                & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0;
+                final List<String> allowlistedRestrictedPermissions =
+                        allowlistAllRestrictedPermissions ? pkg.getRequestedPermissions()
+                        : installArgs.whitelistedRestrictedPermissions;
+                if (allowlistedRestrictedPermissions != null) {
+                    permissionParamsBuilder.setAllowlistedRestrictedPermissions(
+                            allowlistedRestrictedPermissions);
+                }
+                final int autoRevokePermissionsMode = installArgs.autoRevokePermissionsMode;
+                permissionParamsBuilder.setAutoRevokePermissionsMode(autoRevokePermissionsMode);
+                for (int currentUserId : allUsersList) {
+                    if (ps.getInstalled(currentUserId)) {
+                        mPermissionManager.onPackageInstalled(pkg, permissionParamsBuilder.build(),
+                                currentUserId);
+                    }
+                }
             }
             res.name = pkgName;
             res.uid = pkg.getUid();
@@ -19347,6 +19429,8 @@
             mIncrementalManager.unregisterLoadingProgressCallbacks(codePath);
             // Unregister health listener as it will always be healthy from now
             mIncrementalManager.unregisterHealthListener(codePath);
+            // Make sure the information is preserved
+            scheduleWriteSettingsLocked();
         }
 
         @Override
@@ -19409,11 +19493,11 @@
             final PackageSetting ps;
             synchronized (mLock) {
                 ps = mSettings.getPackageLPr(mPackageName);
+                if (ps == null) {
+                    return;
+                }
+                ps.setLoadingProgress(progress);
             }
-            if (ps == null) {
-                return;
-            }
-            ps.setLoadingProgress(progress);
         }
     }
 
@@ -20017,7 +20101,7 @@
             } catch (PackageManagerException pme) {
                 Slog.e(TAG, "Error deriving application ABI", pme);
                 throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
-                        "Error deriving application ABI");
+                        "Error deriving application ABI: " + pme.getMessage());
             }
         }
 
@@ -20906,7 +20990,7 @@
                     extras, 0, null /*targetPackage*/, null, null, null, broadcastAllowList, null);
             packageSender.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, 0,
                     removedPackage, null, null, null, null /* broadcastAllowList */,
-                    getTemporaryAppWhitelistBroadcastOptions().toBundle());
+                    getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED).toBundle());
             if (installerPackageName != null) {
                 packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
                         removedPackage, extras, 0 /*flags*/,
@@ -22614,7 +22698,7 @@
         }
         final Intent intent = getHomeIntent();
         final List<ResolveInfo> resolveInfos = queryIntentActivitiesInternal(intent, null,
-                PackageManager.GET_META_DATA, userId);
+                MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId);
         final ResolveInfo preferredResolveInfo = findPreferredActivityNotLocked(
                 intent, null, 0, resolveInfos, 0, true, false, false, userId);
         final String packageName = preferredResolveInfo != null
@@ -23699,8 +23783,6 @@
         if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
 
         DumpState dumpState = new DumpState();
-        boolean checkin = false;
-
         ArraySet<String> permissionNames = null;
 
         int opti = 0;
@@ -23750,7 +23832,7 @@
                 pw.println("    <package.name>: info about given package");
                 return;
             } else if ("--checkin".equals(opt)) {
-                checkin = true;
+                dumpState.setCheckIn(true);
             } else if ("--all-components".equals(opt)) {
                 dumpState.setOptionEnabled(DumpState.OPTION_DUMP_ALL_COMPONENTS);
             } else if ("-f".equals(opt)) {
@@ -23904,6 +23986,7 @@
         }
 
         final String packageName = dumpState.getTargetPackageName();
+        final boolean checkin = dumpState.isCheckIn();
         if (checkin) {
             pw.println("vers,1");
         }
@@ -23992,11 +24075,7 @@
         }
 
         if (dumpState.isDumping(DumpState.DUMP_LIBS) && packageName == null) {
-            // TODO: Move it to ComputerEngine once LongSparseArray<SharedLibraryInfo> is copied
-            //  in snapshot.
-            synchronized (mLock) {
-                dumpSharedLibrariesLPr(pw, dumpState, checkin);
-            }
+            dump(DumpState.DUMP_LIBS, fd, pw, dumpState);
         }
 
         if (dumpState.isDumping(DumpState.DUMP_FEATURES) && packageName == null) {
@@ -24337,53 +24416,6 @@
         }
     }
 
-    private void dumpSharedLibrariesLPr(PrintWriter pw, DumpState dumpState, boolean checkin) {
-        boolean printedHeader = false;
-        final int numSharedLibraries = mSharedLibraries.size();
-        for (int index = 0; index < numSharedLibraries; index++) {
-            final String libName = mSharedLibraries.keyAt(index);
-            WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(libName);
-            if (versionedLib == null) {
-                continue;
-            }
-            final int versionCount = versionedLib.size();
-            for (int i = 0; i < versionCount; i++) {
-                SharedLibraryInfo libraryInfo = versionedLib.valueAt(i);
-                if (!checkin) {
-                    if (!printedHeader) {
-                        if (dumpState.onTitlePrinted()) {
-                            pw.println();
-                        }
-                        pw.println("Libraries:");
-                        printedHeader = true;
-                    }
-                    pw.print("  ");
-                } else {
-                    pw.print("lib,");
-                }
-                pw.print(libraryInfo.getName());
-                if (libraryInfo.isStatic()) {
-                    pw.print(" version=" + libraryInfo.getLongVersion());
-                }
-                if (!checkin) {
-                    pw.print(" -> ");
-                }
-                if (libraryInfo.getPath() != null) {
-                    if (libraryInfo.isNative()) {
-                        pw.print(" (so) ");
-                    } else {
-                        pw.print(" (jar) ");
-                    }
-                    pw.print(libraryInfo.getPath());
-                } else {
-                    pw.print(" (apk) ");
-                    pw.print(libraryInfo.getPackageName());
-                }
-                pw.println();
-            }
-        }
-    }
-
     // ------- apps on sdcard specific code -------
     static final boolean DEBUG_SD_INSTALL = false;
 
@@ -26097,6 +26129,11 @@
             return PackageManagerService.this.hasSigningCertificate(
                 packageName, certificate, CERT_INPUT_SHA256);
         }
+
+        @Override
+        public boolean hasSystemFeature(String featureName, int version) {
+            return PackageManagerService.this.hasSystemFeature(featureName, version);
+        }
     }
 
     private AndroidPackage getPackage(String packageName) {
@@ -27805,7 +27842,8 @@
         return result.toArray(new PerUidReadTimeouts[result.size()]);
     }
 
-    static @NonNull BroadcastOptions getTemporaryAppWhitelistBroadcastOptions() {
+    static @NonNull BroadcastOptions getTemporaryAppAllowlistBroadcastOptions(
+            @PowerWhitelistManager.ReasonCode int reasonCode) {
         long duration = 10_000;
         final ActivityManagerInternal amInternal =
                 LocalServices.getService(ActivityManagerInternal.class);
@@ -27813,9 +27851,9 @@
             duration = amInternal.getBootTimeTempAllowListDuration();
         }
         final BroadcastOptions bOptions = BroadcastOptions.makeBasic();
-        bOptions.setTemporaryAppWhitelistDuration(
-                BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
-                duration);
+        bOptions.setTemporaryAppAllowlist(duration,
+                TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                reasonCode, "");
         return bOptions;
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index a83a3f8..38e100e 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -787,6 +787,10 @@
         return firstInstallTime;
     }
 
+    public String getName() {
+        return name;
+    }
+
     protected PackageSettingBase updateFrom(PackageSettingBase other) {
         super.copyFrom(other);
         setPath(other.getPath());
diff --git a/services/core/java/com/android/server/pm/ShortcutBitmapSaver.java b/services/core/java/com/android/server/pm/ShortcutBitmapSaver.java
index 1c5f0a7..f411c98 100644
--- a/services/core/java/com/android/server/pm/ShortcutBitmapSaver.java
+++ b/services/core/java/com/android/server/pm/ShortcutBitmapSaver.java
@@ -280,7 +280,8 @@
                     IoUtils.closeQuietly(out);
                 }
 
-                shortcut.setBitmapPath(file.getAbsolutePath());
+                final String path = file.getAbsolutePath();
+                mService.postValue(shortcut, si -> si.setBitmapPath(path));
 
             } catch (IOException | RuntimeException e) {
                 Slog.e(ShortcutService.TAG, "Unable to write bitmap to file", e);
@@ -295,12 +296,14 @@
                 Slog.d(TAG, "Saved bitmap.");
             }
             if (shortcut != null) {
-                if (shortcut.getBitmapPath() == null) {
-                    removeIcon(shortcut);
-                }
+                mService.postValue(shortcut, si -> {
+                    if (si.getBitmapPath() == null) {
+                        removeIcon(si);
+                    }
 
-                // Whatever happened, remove this flag.
-                shortcut.clearFlags(ShortcutInfo.FLAG_ICON_FILE_PENDING_SAVE);
+                    // Whatever happened, remove this flag.
+                    si.clearFlags(ShortcutInfo.FLAG_ICON_FILE_PENDING_SAVE);
+                });
             }
         }
         return true;
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index bb4ec16..302e657 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -19,15 +19,22 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.Person;
+import android.app.appsearch.AppSearchManager;
+import android.app.appsearch.AppSearchSession;
+import android.app.appsearch.PackageIdentifier;
+import android.app.appsearch.SetSchemaRequest;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.LocusId;
+import android.content.pm.AppSearchPerson;
+import android.content.pm.AppSearchShortcutInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.ShortcutInfo;
 import android.content.pm.ShortcutManager;
 import android.content.res.Resources;
 import android.graphics.drawable.Icon;
+import android.os.Binder;
 import android.os.PersistableBundle;
 import android.text.format.Formatter;
 import android.util.ArrayMap;
@@ -39,9 +46,11 @@
 import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.CollectionUtils;
+import com.android.internal.util.ConcurrentUtils;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 import com.android.server.pm.ShortcutService.DumpFilter;
@@ -64,8 +73,12 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.function.Consumer;
+import java.util.function.Function;
 import java.util.function.Predicate;
 
 /**
@@ -155,6 +168,16 @@
 
     private long mLastKnownForegroundElapsedTime;
 
+    private final Object mLock = new Object();
+
+    /**
+     * All external packages that have gained access to the shortcuts from this package
+     */
+    private final Map<String, PackageIdentifier> mPackageIdentifiers = new ArrayMap<>(0);
+
+    @GuardedBy("mLock")
+    private AppSearchSession mAppSearchSession;
+
     private ShortcutPackage(ShortcutUser shortcutUser,
             int packageUserId, String packageName, ShortcutPackageInfo spi) {
         super(shortcutUser, packageUserId, packageName,
@@ -200,12 +223,14 @@
         // - Disable if needed.
         for (int i = mShortcuts.size() - 1; i >= 0; i--) {
             ShortcutInfo si = mShortcuts.valueAt(i);
-            si.clearFlags(ShortcutInfo.FLAG_SHADOW);
+            mutateShortcut(si.getId(), si, shortcut -> {
+                shortcut.clearFlags(ShortcutInfo.FLAG_SHADOW);
 
-            si.setDisabledReason(restoreBlockReason);
-            if (restoreBlockReason != ShortcutInfo.DISABLED_REASON_NOT_DISABLED) {
-                si.addFlags(ShortcutInfo.FLAG_DISABLED);
-            }
+                shortcut.setDisabledReason(restoreBlockReason);
+                if (restoreBlockReason != ShortcutInfo.DISABLED_REASON_NOT_DISABLED) {
+                    shortcut.addFlags(ShortcutInfo.FLAG_DISABLED);
+                }
+            });
         }
         // Because some launchers may not have been restored (e.g. allowBackup=false),
         // we need to re-calculate the pinned shortcuts.
@@ -437,9 +462,11 @@
             if (si.isDynamic() && (!ignoreInvisible || si.isVisibleToPublisher())) {
                 changed = true;
 
-                si.setTimestamp(now);
-                si.clearFlags(ShortcutInfo.FLAG_DYNAMIC);
-                si.setRank(0); // It may still be pinned, so clear the rank.
+                mutateShortcut(si.getId(), si, shortcut -> {
+                    shortcut.setTimestamp(now);
+                    shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC);
+                    shortcut.setRank(0); // It may still be pinned, so clear the rank.
+                });
             }
         }
         if (changed) {
@@ -483,7 +510,7 @@
     public ShortcutInfo deleteLongLivedWithId(@NonNull String shortcutId, boolean ignoreInvisible) {
         final ShortcutInfo shortcut = mShortcuts.get(shortcutId);
         if (shortcut != null) {
-            shortcut.clearFlags(ShortcutInfo.FLAG_CACHED_ALL);
+            mutateShortcut(shortcutId, null, si -> si.clearFlags(ShortcutInfo.FLAG_CACHED_ALL));
         }
         return deleteOrDisableWithId(
                 shortcutId, /* disable =*/ false, /* overrideImmutable=*/ false, ignoreInvisible,
@@ -504,15 +531,16 @@
                 overrideImmutable, ignoreInvisible, disabledReason);
 
         // If disabled id still exists, it is pinned and we need to update the disabled message.
-        final ShortcutInfo disabled = mShortcuts.get(shortcutId);
-        if (disabled != null) {
-            if (disabledMessage != null) {
-                disabled.setDisabledMessage(disabledMessage);
-            } else if (disabledMessageResId != 0) {
-                disabled.setDisabledMessageResId(disabledMessageResId);
-                mShortcutUser.mService.fixUpShortcutResourceNamesAndValues(disabled);
+        mutateShortcut(shortcutId, null, disabled -> {
+            if (disabled != null) {
+                if (disabledMessage != null) {
+                    disabled.setDisabledMessage(disabledMessage);
+                } else if (disabledMessageResId != 0) {
+                    disabled.setDisabledMessageResId(disabledMessageResId);
+                    mShortcutUser.mService.fixUpShortcutResourceNamesAndValues(disabled);
+                }
             }
-        }
+        });
 
         return deleted;
     }
@@ -534,21 +562,23 @@
         }
         if (oldShortcut.isPinned() || oldShortcut.isCached()) {
 
-            oldShortcut.setRank(0);
-            oldShortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_MANIFEST);
-            if (disable) {
-                oldShortcut.addFlags(ShortcutInfo.FLAG_DISABLED);
-                // Do not overwrite the disabled reason if one is alreay set.
-                if (oldShortcut.getDisabledReason() == ShortcutInfo.DISABLED_REASON_NOT_DISABLED) {
-                    oldShortcut.setDisabledReason(disabledReason);
+            mutateShortcut(oldShortcut.getId(), oldShortcut, si -> {
+                si.setRank(0);
+                si.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_MANIFEST);
+                if (disable) {
+                    si.addFlags(ShortcutInfo.FLAG_DISABLED);
+                    // Do not overwrite the disabled reason if one is alreay set.
+                    if (si.getDisabledReason() == ShortcutInfo.DISABLED_REASON_NOT_DISABLED) {
+                        si.setDisabledReason(disabledReason);
+                    }
                 }
-            }
-            oldShortcut.setTimestamp(mShortcutUser.mService.injectCurrentTimeMillis());
+                si.setTimestamp(mShortcutUser.mService.injectCurrentTimeMillis());
 
-            // See ShortcutRequestPinProcessor.directPinShortcut().
-            if (mShortcutUser.mService.isDummyMainActivity(oldShortcut.getActivity())) {
-                oldShortcut.setActivity(null);
-            }
+                // See ShortcutRequestPinProcessor.directPinShortcut().
+                if (mShortcutUser.mService.isDummyMainActivity(si.getActivity())) {
+                    si.setActivity(null);
+                }
+            });
 
             return null;
         } else {
@@ -558,12 +588,11 @@
     }
 
     public void enableWithId(@NonNull String shortcutId) {
-        final ShortcutInfo shortcut = mShortcuts.get(shortcutId);
-        if (shortcut != null) {
-            ensureNotImmutable(shortcut, /*ignoreInvisible=*/ true);
-            shortcut.clearFlags(ShortcutInfo.FLAG_DISABLED);
-            shortcut.setDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED);
-        }
+        mutateShortcut(shortcutId, null, si -> {
+            ensureNotImmutable(si, /*ignoreInvisible=*/ true);
+            si.clearFlags(ShortcutInfo.FLAG_DISABLED);
+            si.setDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED);
+        });
     }
 
     public void updateInvisibleShortcutForPinRequestWith(@NonNull ShortcutInfo shortcut) {
@@ -586,22 +615,25 @@
      * <p>Then remove all shortcuts that are not dynamic and no longer pinned either.
      */
     public void refreshPinnedFlags() {
-        // First, un-pin all shortcuts
-        for (int i = mShortcuts.size() - 1; i >= 0; i--) {
-            mShortcuts.valueAt(i).clearFlags(ShortcutInfo.FLAG_PINNED);
+        // TODO: rewrite this function with proper query (i.e. fetch only pinned shortcuts and
+        //  unpin if it's no longer pinned by any launcher and vice versa)
+        final List<ShortcutInfo> shortcuts = new ArrayList<>(mShortcuts.values());
+        final Map<String, ShortcutInfo> shortcutMap = new ArrayMap<>(shortcuts.size());
+        for (ShortcutInfo si : shortcuts) {
+            shortcutMap.put(si.getId(), si);
         }
+        final Set<String> pinnedShortcuts = new ArraySet<>();
 
-        // Then, for the pinned set for each launcher, set the pin flag one by one.
+        // First, for the pinned set for each launcher, keep track of their id one by one.
         mShortcutUser.forAllLaunchers(launcherShortcuts -> {
             final ArraySet<String> pinned = launcherShortcuts.getPinnedShortcutIds(
                     getPackageName(), getPackageUserId());
-
             if (pinned == null || pinned.size() == 0) {
                 return;
             }
             for (int i = pinned.size() - 1; i >= 0; i--) {
                 final String id = pinned.valueAt(i);
-                final ShortcutInfo si = mShortcuts.get(id);
+                final ShortcutInfo si = shortcutMap.get(id);
                 if (si == null) {
                     // This happens if a launcher pinned shortcuts from this package, then backup&
                     // restored, but this package doesn't allow backing up.
@@ -609,9 +641,21 @@
                     // That's fine, when the launcher is restored, we'll fix it.
                     continue;
                 }
-                si.addFlags(ShortcutInfo.FLAG_PINNED);
+                pinnedShortcuts.add(si.getId());
             }
         });
+        // Then, update the pinned state if necessary
+        for (int i = shortcuts.size() - 1; i >= 0; i--) {
+            final ShortcutInfo si = shortcuts.get(i);
+            if (pinnedShortcuts.contains(si.getId()) && !si.isPinned()) {
+                mutateShortcut(si.getId(), si,
+                        shortcut -> shortcut.addFlags(ShortcutInfo.FLAG_PINNED));
+            }
+            if (!pinnedShortcuts.contains(si.getId()) && si.isPinned()) {
+                mutateShortcut(si.getId(), si, shortcut ->
+                        shortcut.clearFlags(ShortcutInfo.FLAG_PINNED));
+            }
+        }
 
         // Lastly, remove the ones that are no longer pinned, cached nor dynamic.
         removeOrphans();
@@ -1011,8 +1055,10 @@
                 continue;
             }
             Slog.i(TAG, String.format("Restoring shortcut: %s", si.getId()));
-            si.clearFlags(ShortcutInfo.FLAG_DISABLED);
-            si.setDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED);
+            mutateShortcut(si.getId(), si, shortcut -> {
+                shortcut.clearFlags(ShortcutInfo.FLAG_DISABLED);
+                shortcut.setDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED);
+            });
         }
 
         // For existing shortcuts, update timestamps if they have any resources.
@@ -1042,21 +1088,24 @@
                 }
 
                 if (si.hasAnyResources()) {
-                    if (!si.isOriginallyFromManifest()) {
+                    if (publisherRes == null) {
+                        publisherRes = getPackageResources();
                         if (publisherRes == null) {
-                            publisherRes = getPackageResources();
-                            if (publisherRes == null) {
-                                break; // Resources couldn't be loaded.
-                            }
+                            break; // Resources couldn't be loaded.
+                        }
+                    }
+
+                    final Resources res = publisherRes;
+                    mutateShortcut(si.getId(), si, shortcut -> {
+                        if (!shortcut.isOriginallyFromManifest()) {
+                            shortcut.lookupAndFillInResourceIds(res);
                         }
 
-                        // TODO: update resource strings in AppSearch
                         // If this shortcut is not from a manifest, then update all resource IDs
                         // from resource names.  (We don't allow resource strings for
                         // non-manifest at the moment, but icons can still be resources.)
-                        si.lookupAndFillInResourceIds(publisherRes);
-                    }
-                    si.setTimestamp(s.injectCurrentTimeMillis());
+                        shortcut.setTimestamp(s.injectCurrentTimeMillis());
+                    });
                 }
             }
         }
@@ -1359,8 +1408,11 @@
                     }
                 }
 
-                si.resolveResourceStrings(publisherRes);
-                si.setTimestamp(s.injectCurrentTimeMillis());
+                final Resources res = publisherRes;
+                mutateShortcut(si.getId(), si, shortcut -> {
+                    shortcut.resolveResourceStrings(res);
+                    shortcut.setTimestamp(s.injectCurrentTimeMillis());
+                });
 
                 if (changedShortcuts == null) {
                     changedShortcuts = new ArrayList<>(1);
@@ -1377,7 +1429,7 @@
     public void clearAllImplicitRanks() {
         for (int i = mShortcuts.size() - 1; i >= 0; i--) {
             final ShortcutInfo si = mShortcuts.valueAt(i);
-            si.clearImplicitRankAndRankChangedFlag();
+            mutateShortcut(si.getId(), si, ShortcutInfo::clearImplicitRankAndRankChangedFlag);
         }
     }
 
@@ -1422,8 +1474,10 @@
             final ShortcutInfo si = mShortcuts.valueAt(i);
             if (si.isFloating()) {
                 if (si.getRank() != 0) {
-                    si.setTimestamp(now);
-                    si.setRank(0);
+                    mutateShortcut(si.getId(), si, shortcut -> {
+                        shortcut.setTimestamp(now);
+                        shortcut.setRank(0);
+                    });
                 }
             }
         }
@@ -1456,8 +1510,10 @@
                 }
                 final int thisRank = rank++;
                 if (si.getRank() != thisRank) {
-                    si.setTimestamp(now);
-                    si.setRank(thisRank);
+                    mutateShortcut(si.getId(), si, shortcut -> {
+                        shortcut.setTimestamp(now);
+                        shortcut.setRank(thisRank);
+                    });
                 }
             }
         }
@@ -2140,6 +2196,41 @@
         }
     }
 
+    void updateVisibility(String packageName, byte[] certificate, boolean visible) {
+        if (visible) {
+            mPackageIdentifiers.put(packageName, new PackageIdentifier(packageName, certificate));
+        } else {
+            mPackageIdentifiers.remove(packageName);
+        }
+        resetAppSearch(null);
+    }
+
+    void mutateShortcut(@NonNull final String id, @Nullable final ShortcutInfo shortcut,
+            @NonNull final Consumer<ShortcutInfo> transform) {
+        Objects.requireNonNull(id);
+        Objects.requireNonNull(transform);
+        synchronized (mLock) {
+            if (shortcut != null) {
+                transform.accept(shortcut);
+            } else {
+                transform.accept(findShortcutById(id));
+            }
+            // TODO: Load ShortcutInfo from AppSearch, apply transformation logic and save
+        }
+    }
+
+    /**
+     * Removes shortcuts from AppSearch.
+     */
+    void removeShortcuts() {
+    }
+
+    /**
+     * Merge/replace shortcuts parsed from xml file.
+     */
+    void restoreParsedShortcuts(final boolean replace) {
+    }
+
     private boolean verifyRanksSequential(List<ShortcutInfo> list) {
         boolean failed = false;
 
@@ -2153,4 +2244,128 @@
         }
         return failed;
     }
+
+    private void runInAppSearch(
+            Function<SearchSessionObservable, Consumer<AppSearchSession>>... observers) {
+        if (mShortcutUser == null) {
+            Slog.w(TAG, "shortcut user is null");
+            return;
+        }
+        synchronized (mLock) {
+            if (mAppSearchSession != null) {
+                final CountDownLatch latch = new CountDownLatch(1);
+                final long callingIdentity = Binder.clearCallingIdentity();
+                try {
+                    final SearchSessionObservable upstream =
+                            new SearchSessionObservable(mAppSearchSession, latch);
+                    for (Function<SearchSessionObservable, Consumer<AppSearchSession>> observer
+                            : observers) {
+                        upstream.map(observer);
+                    }
+                    upstream.next();
+                } finally {
+                    Binder.restoreCallingIdentity(callingIdentity);
+                }
+                ConcurrentUtils.waitForCountDownNoInterrupt(latch, 500,
+                        "timeout accessing shortcut");
+            } else {
+                resetAppSearch(observers);
+            }
+        }
+    }
+
+    private void resetAppSearch(
+            Function<SearchSessionObservable, Consumer<AppSearchSession>>... observers) {
+        final CountDownLatch latch = new CountDownLatch(1);
+        final AppSearchManager.SearchContext searchContext =
+                new AppSearchManager.SearchContext.Builder()
+                        .setDatabaseName(getPackageName()).build();
+        mShortcutUser.runInAppSearch(searchContext, result -> {
+            if (!result.isSuccess()) {
+                Slog.e(TAG, "error getting search session during lazy init, "
+                        + result.getErrorMessage());
+                latch.countDown();
+                return;
+            }
+            // TODO: Flatten callback chain with proper async framework
+            final SearchSessionObservable upstream =
+                    new SearchSessionObservable(result.getResultValue(), latch)
+                            .map(this::setupSchema);
+            if (observers != null) {
+                for (Function<SearchSessionObservable, Consumer<AppSearchSession>> observer
+                        : observers) {
+                    upstream.map(observer);
+                }
+            }
+            upstream.map(observable -> session -> {
+                mAppSearchSession = session;
+                observable.next();
+            });
+            upstream.next();
+        });
+        ConcurrentUtils.waitForCountDownNoInterrupt(latch, 1500,
+                "timeout accessing shortcut during lazy initialization");
+    }
+
+    /**
+     * creates the schema for shortcut in the database
+     */
+    private Consumer<AppSearchSession> setupSchema(SearchSessionObservable observable) {
+        return session -> {
+            SetSchemaRequest.Builder schemaBuilder = new SetSchemaRequest.Builder()
+                            .addSchemas(AppSearchPerson.SCHEMA, AppSearchShortcutInfo.SCHEMA);
+            for (PackageIdentifier pi : mPackageIdentifiers.values()) {
+                schemaBuilder = schemaBuilder
+                        .setSchemaTypeVisibilityForPackage(
+                                AppSearchPerson.SCHEMA_TYPE, true, pi)
+                        .setSchemaTypeVisibilityForPackage(
+                                AppSearchShortcutInfo.SCHEMA_TYPE, true, pi);
+            }
+            session.setSchema(schemaBuilder.build(), mShortcutUser.mExecutor, result -> {
+                if (!result.isSuccess()) {
+                    observable.error("failed to instantiate app search schema: "
+                            + result.getErrorMessage());
+                    return;
+                }
+                observable.next();
+            });
+        };
+    }
+
+    /**
+     * TODO: Replace this temporary implementation with proper async framework
+     */
+    private class SearchSessionObservable {
+
+        final AppSearchSession mSession;
+        final CountDownLatch mLatch;
+        final ArrayList<Consumer<AppSearchSession>> mObservers = new ArrayList<>(1);
+
+        SearchSessionObservable(@NonNull final AppSearchSession session,
+                @NonNull final CountDownLatch latch) {
+            mSession = session;
+            mLatch = latch;
+        }
+
+        SearchSessionObservable map(
+                Function<SearchSessionObservable, Consumer<AppSearchSession>> observer) {
+            mObservers.add(observer.apply(this));
+            return this;
+        }
+
+        void next() {
+            if (mObservers.isEmpty()) {
+                mLatch.countDown();
+                return;
+            }
+            mObservers.remove(0).accept(mSession);
+        }
+
+        void error(@Nullable final String errorMessage) {
+            if (errorMessage != null) {
+                Slog.e(TAG, errorMessage);
+            }
+            mLatch.countDown();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 4d8abea..a377f1c 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -362,6 +362,7 @@
     private List<Integer> mDirtyUserIds = new ArrayList<>();
 
     private final AtomicBoolean mBootCompleted = new AtomicBoolean();
+    private final AtomicBoolean mShutdown = new AtomicBoolean();
 
     /**
      * Note we use a fine-grained lock for {@link #mUnlockedUsers} due to b/64303666.
@@ -498,6 +499,12 @@
         mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL,
                 localeFilter, null, mHandler);
 
+        IntentFilter shutdownFilter = new IntentFilter();
+        shutdownFilter.addAction(Intent.ACTION_SHUTDOWN);
+        shutdownFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+        mContext.registerReceiverAsUser(mShutdownReceiver, UserHandle.SYSTEM,
+                shutdownFilter, null, mHandler);
+
         injectRegisterUidObserver(mUidObserver, ActivityManager.UID_OBSERVER_PROCSTATE
                 | ActivityManager.UID_OBSERVER_GONE);
 
@@ -662,7 +669,7 @@
     /** lifecycle event */
     void handleUnlockUser(int userId) {
         if (DEBUG) {
-        Slog.d(TAG, "handleUnlockUser: user=" + userId);
+            Slog.d(TAG, "handleUnlockUser: user=" + userId);
         }
         synchronized (mUnlockedUsers) {
             mUnlockedUsers.put(userId, true);
@@ -1162,6 +1169,9 @@
         if (DEBUG) {
             Slog.d(TAG, "saveDirtyInfo");
         }
+        if (mShutdown.get()) {
+            return;
+        }
         try {
             synchronized (mLock) {
                 for (int i = mDirtyUserIds.size() - 1; i >= 0; i--) {
@@ -1179,6 +1189,14 @@
         }
     }
 
+    void postValue(@NonNull final ShortcutInfo shortcutInfo,
+            @NonNull final Consumer<ShortcutInfo> cb) {
+        final String pkg = shortcutInfo.getPackage();
+        final int userId = shortcutInfo.getUserId();
+        final String id = shortcutInfo.getId();
+        getPackageShortcutsLocked(pkg, userId).mutateShortcut(id, shortcutInfo, cb);
+    }
+
     /** Return the last reset time. */
     @GuardedBy("mLock")
     long getLastResetTimeLocked() {
@@ -1566,7 +1584,6 @@
      * resource-based strings.
      */
     void fixUpShortcutResourceNamesAndValues(ShortcutInfo si) {
-        // TODO: update resource names in AppSearch
         final Resources publisherRes = injectGetResourcesForApplicationAsUser(
                 si.getPackage(), si.getUserId());
         if (publisherRes != null) {
@@ -1947,7 +1964,7 @@
         final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission(
                 injectBinderCallingPid(), injectBinderCallingUid());
 
-        List<ShortcutInfo> changedShortcuts = null;
+        final List<ShortcutInfo> changedShortcuts = new ArrayList<>(1);
 
         synchronized (mLock) {
             throwIfUserLockedL(userId);
@@ -1975,59 +1992,57 @@
                 final ShortcutInfo source = newShortcuts.get(i);
                 fixUpIncomingShortcutInfo(source, /* forUpdate= */ true);
 
-                final ShortcutInfo target = ps.findShortcutById(source.getId());
+                ps.mutateShortcut(source.getId(), null, target -> {
+                    // Invisible shortcuts can't be updated.
+                    if (target == null || !target.isVisibleToPublisher()) {
+                        return;
+                    }
 
-                // Invisible shortcuts can't be updated.
-                if (target == null || !target.isVisibleToPublisher()) {
-                    continue;
-                }
+                    if (target.isEnabled() != source.isEnabled()) {
+                        Slog.w(TAG,
+                                "ShortcutInfo.enabled cannot be changed with updateShortcuts()");
+                    }
 
-                if (target.isEnabled() != source.isEnabled()) {
-                    Slog.w(TAG,
-                            "ShortcutInfo.enabled cannot be changed with updateShortcuts()");
-                }
+                    if (target.isLongLived() != source.isLongLived()) {
+                        Slog.w(TAG,
+                                "ShortcutInfo.longLived cannot be changed with updateShortcuts()");
+                    }
 
-                if (target.isLongLived() != source.isLongLived()) {
-                    Slog.w(TAG,
-                            "ShortcutInfo.longLived cannot be changed with updateShortcuts()");
-                }
+                    // When updating the rank, we need to insert between existing ranks, so set
+                    // this setRankChanged, and also copy the implicit rank fo adjustRanks().
+                    if (source.hasRank()) {
+                        target.setRankChanged();
+                        target.setImplicitRank(source.getImplicitRank());
+                    }
 
-                // When updating the rank, we need to insert between existing ranks, so set
-                // this setRankChanged, and also copy the implicit rank fo adjustRanks().
-                if (source.hasRank()) {
-                    target.setRankChanged();
-                    target.setImplicitRank(source.getImplicitRank());
-                }
+                    final boolean replacingIcon = (source.getIcon() != null);
+                    if (replacingIcon) {
+                        removeIconLocked(target);
+                    }
 
-                final boolean replacingIcon = (source.getIcon() != null);
-                if (replacingIcon) {
-                    removeIconLocked(target);
-                }
+                    // Note copyNonNullFieldsFrom() does the "updatable with?" check too.
+                    target.copyNonNullFieldsFrom(source);
+                    target.setTimestamp(injectCurrentTimeMillis());
 
-                // Note copyNonNullFieldsFrom() does the "updatable with?" check too.
-                target.copyNonNullFieldsFrom(source);
-                target.setTimestamp(injectCurrentTimeMillis());
+                    if (replacingIcon) {
+                        saveIconAndFixUpShortcutLocked(target);
+                    }
 
-                if (replacingIcon) {
-                    saveIconAndFixUpShortcutLocked(target);
-                }
+                    // When we're updating any resource related fields, re-extract the res names and
+                    // the values.
+                    if (replacingIcon || source.hasStringResources()) {
+                        fixUpShortcutResourceNamesAndValues(target);
+                    }
 
-                // When we're updating any resource related fields, re-extract the res names and
-                // the values.
-                if (replacingIcon || source.hasStringResources()) {
-                    fixUpShortcutResourceNamesAndValues(target);
-                }
-
-                if (changedShortcuts == null) {
-                    changedShortcuts = new ArrayList<>(1);
-                }
-                changedShortcuts.add(target);
+                    changedShortcuts.add(target);
+                });
             }
 
             // Lastly, adjust the ranks.
             ps.adjustRanks();
         }
-        packageShortcutsChanged(packageName, userId, changedShortcuts, null);
+        packageShortcutsChanged(packageName, userId,
+                changedShortcuts.isEmpty() ? null : changedShortcuts, null);
 
         verifyStates();
 
@@ -2150,6 +2165,15 @@
     }
 
     @Override
+    public void updateShortcutVisibility(String callingPkg, String packageName, byte[] certificate,
+            boolean visible, int userId) {
+        synchronized (mLock) {
+            getPackageShortcutsForPublisherLocked(callingPkg, userId)
+                    .updateVisibility(packageName, certificate, visible);
+        }
+    }
+
+    @Override
     public boolean requestPinShortcut(String packageName, ShortcutInfo shortcut,
             IntentSender resultIntent, int userId) {
         Objects.requireNonNull(shortcut);
@@ -3105,7 +3129,8 @@
 
                     if (doCache) {
                         if (si.isLongLived()) {
-                            si.addFlags(cacheFlags);
+                            sp.mutateShortcut(si.getId(), si,
+                                    shortcut -> shortcut.addFlags(cacheFlags));
                             if (changedShortcuts == null) {
                                 changedShortcuts = new ArrayList<>(1);
                             }
@@ -3116,7 +3141,8 @@
                         }
                     } else {
                         ShortcutInfo removed = null;
-                        si.clearFlags(cacheFlags);
+                        sp.mutateShortcut(si.getId(), si, shortcut ->
+                                shortcut.clearFlags(cacheFlags));
                         if (!si.isDynamic() && !si.isCached()) {
                             removed = sp.deleteLongLivedWithId(id, /*ignoreInvisible=*/ true);
                         }
@@ -3478,6 +3504,22 @@
         }
     };
 
+    private final BroadcastReceiver mShutdownReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            // Since it cleans up the shortcut directory and rewrite the ShortcutPackageItems
+            // in odrder during saveToXml(), it could lead to shortcuts missing when shutdown.
+            // We need it so that it can finish up saving before shutdown.
+            synchronized (mLock) {
+                if (mHandler.hasCallbacks(mSaveDirtyInfoRunner)) {
+                    mHandler.removeCallbacks(mSaveDirtyInfoRunner);
+                    saveDirtyInfo();
+                }
+                mShutdown.set(true);
+            }
+        }
+    };
+
     /**
      * Called when a user is unlocked.
      * - Check all known packages still exist, and otherwise perform cleanup.
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 3e3aa67..ec784d0 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -18,9 +18,14 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.appsearch.AppSearchManager;
+import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.AppSearchSession;
 import android.content.pm.ShortcutManager;
 import android.metrics.LogMaker;
+import android.os.Binder;
 import android.os.FileUtils;
+import android.os.UserHandle;
 import android.text.TextUtils;
 import android.text.format.Formatter;
 import android.util.ArrayMap;
@@ -32,6 +37,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.server.FgThread;
 import com.android.server.pm.ShortcutService.DumpFilter;
 import com.android.server.pm.ShortcutService.InvalidFileFormatException;
 
@@ -45,6 +51,7 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.Objects;
+import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 
 /**
@@ -111,6 +118,8 @@
     }
 
     final ShortcutService mService;
+    final AppSearchManager mAppSearchManager;
+    final Executor mExecutor;
 
     @UserIdInt
     private final int mUserId;
@@ -132,6 +141,9 @@
     public ShortcutUser(ShortcutService service, int userId) {
         mService = service;
         mUserId = userId;
+        mAppSearchManager = service.mContext.createContextAsUser(UserHandle.of(userId), 0)
+                .getSystemService(AppSearchManager.class);
+        mExecutor = FgThread.getExecutor();
     }
 
     public int getUserId() {
@@ -173,6 +185,9 @@
     public ShortcutPackage removePackage(@NonNull String packageName) {
         final ShortcutPackage removed = mPackages.remove(packageName);
 
+        if (removed != null) {
+            removed.removeShortcuts();
+        }
         mService.cleanupBitmapsForPackage(mUserId, packageName);
 
         return removed;
@@ -318,7 +333,10 @@
 
         if (!shortcutPackage.rescanPackageIfNeeded(isNewApp, forceRescan)) {
             if (isNewApp) {
-                mPackages.remove(packageName);
+                final ShortcutPackage sp = mPackages.remove(packageName);
+                if (sp != null) {
+                    sp.removeShortcuts();
+                }
             }
         }
     }
@@ -442,6 +460,7 @@
                         case ShortcutPackage.TAG_ROOT: {
                             final ShortcutPackage shortcuts = ShortcutPackage.loadFromXml(
                                     s, ret, parser, fromBackup);
+                            shortcuts.restoreParsedShortcuts(false);
 
                             // Don't use addShortcut(), we don't need to save the icon.
                             ret.mPackages.put(shortcuts.getPackageName(), shortcuts);
@@ -476,6 +495,7 @@
                 final ShortcutPackage sp = ShortcutPackage.loadFromFile(s, ret, f, fromBackup);
                 if (sp != null) {
                     ret.mPackages.put(sp.getPackageName(), sp);
+                    sp.restoreParsedShortcuts(false);
                 }
             });
 
@@ -558,6 +578,7 @@
                 Log.w(TAG, "Shortcuts for package " + sp.getPackageName() + " are being restored."
                         + " Existing non-manifeset shortcuts will be overwritten.");
             }
+            sp.restoreParsedShortcuts(true);
             addPackage(sp);
             restoredPackages[0]++;
             restoredShortcuts[0] += sp.getShortcutCount();
@@ -693,4 +714,18 @@
         logger.write(logMaker.setType(MetricsEvent.SHORTCUTS_CHANGED_SHORTCUT_COUNT)
                 .setSubtype(totalSharingShortcutCount));
     }
+
+    void runInAppSearch(@NonNull final AppSearchManager.SearchContext searchContext,
+            @NonNull final Consumer<AppSearchResult<AppSearchSession>> callback) {
+        if (mAppSearchManager == null) {
+            Slog.e(TAG, "app search manager is null");
+            return;
+        }
+        final long callingIdentity = Binder.clearCallingIdentity();
+        try {
+            mAppSearchManager.createSearchSession(searchContext, mExecutor, callback);
+        } finally {
+            Binder.restoreCallingIdentity(callingIdentity);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index c17d2e4..eb2de60 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -63,8 +63,13 @@
      */
     public interface UserLifecycleListener {
 
-        /** Called when a new user is created. */
-        default void onUserCreated(UserInfo user) {}
+        /**
+         * Called when a new user is created.
+         *
+         * @param user new user.
+         * @param token token passed to the method that created the user.
+         */
+        default void onUserCreated(UserInfo user, @Nullable Object token) {}
 
         /** Called when an existing user is removed. */
         default void onUserRemoved(UserInfo user) {}
@@ -179,10 +184,12 @@
      * {@link UserManager#DISALLOW_ADD_USER} and {@link UserManager#DISALLOW_ADD_MANAGED_PROFILE}
      *
      * <p>Called by the {@link com.android.server.devicepolicy.DevicePolicyManagerService} when
-     * createAndManageUser is called by the device owner.
+     * createAndManageUser is called by the device owner; it uses {@code token} to block until
+     * the user is created (as it will be passed back to it through
+     * {@link UserLifecycleListener#onUserCreated(UserInfo, Object)});
      */
     public abstract UserInfo createUserEvenWhenDisallowed(String name, String userType,
-            int flags, String[] disallowedPackages)
+            int flags, String[] disallowedPackages, @Nullable Object token)
             throws UserManager.CheckedUserOperationException;
 
     /**
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 24c27be..871576e 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -983,7 +983,11 @@
 
     @Override
     public UserInfo getProfileParent(@UserIdInt int userId) {
-        checkManageUsersPermission("get the profile parent");
+        if (!hasManageUsersOrPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)) {
+            throw new SecurityException(
+                    "You need MANAGE_USERS or INTERACT_ACROSS_USERS permission to get the "
+                            + "profile parent");
+        }
         synchronized (mUsersLock) {
             return getProfileParentLU(userId);
         }
@@ -1522,20 +1526,30 @@
     }
 
     @Override
-    public boolean isUserForeground() {
-        int callingUserId = Binder.getCallingUserHandle().getIdentifier();
+    public boolean isUserForeground(@UserIdInt int userId) {
+        final int callingUserId = UserHandle.getCallingUserId();
+        if (callingUserId != userId
+                && !hasManageUsersOrPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)) {
+            throw new SecurityException("Caller from user " + callingUserId + " needs MANAGE_USERS "
+                    + "or INTERACT_ACROSS_USERS permission to check if another user (" + userId
+                    + ") is running in the foreground");
+        }
+
         int currentUser = Binder.withCleanCallingIdentity(() -> ActivityManager.getCurrentUser());
         // TODO(b/179163496): should return true for profile users of the current user as well
-        return currentUser == callingUserId;
+        return currentUser == userId;
     }
 
     @Override
     public String getUserName() {
-        if (!hasManageUsersOrPermission(android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED)) {
-            throw new SecurityException("You need MANAGE_USERS or GET_ACCOUNTS_PRIVILEGED "
-                    + "permissions to: get user name");
+        final int callingUid = Binder.getCallingUid();
+        if (!hasManageOrCreateUsersPermission()
+                || hasPermissionGranted(
+                        android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED, callingUid)) {
+            throw new SecurityException("You need MANAGE_USERS or CREATE_USERS or "
+                    + "GET_ACCOUNTS_PRIVILEGED permissions to: get user name");
         }
-        final int userId = UserHandle.getUserId(Binder.getCallingUid());
+        final int userId = UserHandle.getUserId(callingUid);
         synchronized (mUsersLock) {
             UserInfo userInfo = userWithName(getUserInfoLU(userId));
             return userInfo == null ? "" : userInfo.name;
@@ -3287,7 +3301,7 @@
      * as well as for {@link UserManager#USER_TYPE_FULL_RESTRICTED}.
      */
     @Override
-    public UserInfo createProfileForUserWithThrow(String name, @NonNull String userType,
+    public UserInfo createProfileForUserWithThrow(@Nullable String name, @NonNull String userType,
             @UserInfoFlag int flags, @UserIdInt int userId, @Nullable String[] disallowedPackages)
             throws ServiceSpecificException {
         checkManageOrCreateUsersPermission(flags);
@@ -3309,7 +3323,7 @@
         checkManageOrCreateUsersPermission(flags);
         try {
             return createUserInternalUnchecked(name, userType, flags, userId,
-                    /* preCreate= */ false, disallowedPackages);
+                    /* preCreate= */ false, disallowedPackages, /* token= */ null);
         } catch (UserManager.CheckedUserOperationException e) {
             throw e.toServiceSpecificException();
         }
@@ -3342,7 +3356,7 @@
         try {
             return createUserInternalUnchecked(/* name= */ null, userType, flags,
                     /* parentId= */ UserHandle.USER_NULL, /* preCreate= */ true,
-                    /* disallowedPackages= */ null);
+                    /* disallowedPackages= */ null, /* token= */ null);
         } catch (UserManager.CheckedUserOperationException e) {
             throw e.toServiceSpecificException();
         }
@@ -3358,12 +3372,13 @@
         enforceUserRestriction(restriction, UserHandle.getCallingUserId(),
                 "Cannot add user");
         return createUserInternalUnchecked(name, userType, flags, parentId,
-                /* preCreate= */ false, disallowedPackages);
+                /* preCreate= */ false, disallowedPackages, /* token= */ null);
     }
 
     private UserInfo createUserInternalUnchecked(@Nullable String name,
             @NonNull String userType, @UserInfoFlag int flags, @UserIdInt int parentId,
-            boolean preCreate, @Nullable String[] disallowedPackages)
+            boolean preCreate, @Nullable String[] disallowedPackages,
+            @Nullable Object token)
             throws UserManager.CheckedUserOperationException {
         final int nextProbableUserId = getNextAvailableId();
         final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
@@ -3372,7 +3387,7 @@
         UserInfo newUser = null;
         try {
             newUser = createUserInternalUncheckedNoTracing(name, userType, flags, parentId,
-                        preCreate, disallowedPackages, t);
+                        preCreate, disallowedPackages, t, token);
             return newUser;
         } finally {
             logUserCreateJourneyFinish(sessionId, nextProbableUserId, newUser != null);
@@ -3383,7 +3398,8 @@
     private UserInfo createUserInternalUncheckedNoTracing(@Nullable String name,
             @NonNull String userType, @UserInfoFlag int flags, @UserIdInt int parentId,
             boolean preCreate, @Nullable String[] disallowedPackages,
-            @NonNull TimingsTraceAndSlog t) throws UserManager.CheckedUserOperationException {
+            @NonNull TimingsTraceAndSlog t, @Nullable Object token)
+                    throws UserManager.CheckedUserOperationException {
         final UserTypeDetails userTypeDetails = mUserTypes.get(userType);
         if (userTypeDetails == null) {
             Slog.e(LOG_TAG, "Cannot create user of invalid user type: " + userType);
@@ -3409,7 +3425,8 @@
 
         // Try to use a pre-created user (if available).
         if (!preCreate && parentId < 0 && isUserTypeEligibleForPreCreation(userTypeDetails)) {
-            final UserInfo preCreatedUser = convertPreCreatedUserIfPossible(userType, flags, name);
+            final UserInfo preCreatedUser = convertPreCreatedUserIfPossible(userType, flags, name,
+                    token);
             if (preCreatedUser != null) {
                 return preCreatedUser;
             }
@@ -3588,7 +3605,7 @@
                     Slog.w(LOG_TAG, "could not start pre-created user " + userId, e);
                 }
             } else {
-                dispatchUserAdded(userInfo);
+                dispatchUserAdded(userInfo, token);
             }
 
         } finally {
@@ -3688,7 +3705,7 @@
      * @return the converted user, or {@code null} if no pre-created user could be converted.
      */
     private @Nullable UserInfo convertPreCreatedUserIfPossible(String userType,
-            @UserInfoFlag int flags, String name) {
+            @UserInfoFlag int flags, String name, @Nullable Object token) {
         final UserData preCreatedUserData;
         synchronized (mUsersLock) {
             preCreatedUserData = getPreCreatedUserLU(userType);
@@ -3726,7 +3743,7 @@
         }
         updateUserIds();
         mPm.onNewUserCreated(preCreatedUser.id, /* convertedFromPreCreated= */ true);
-        dispatchUserAdded(preCreatedUser);
+        dispatchUserAdded(preCreatedUser, token);
         return preCreatedUser;
     }
 
@@ -3758,11 +3775,11 @@
         return (now > EPOCH_PLUS_30_YEARS) ? now : 0;
     }
 
-    private void dispatchUserAdded(@NonNull UserInfo userInfo) {
+    private void dispatchUserAdded(@NonNull UserInfo userInfo, @Nullable Object token) {
         // Notify internal listeners first...
         synchronized (mUserLifecycleListeners) {
             for (int i = 0; i < mUserLifecycleListeners.size(); i++) {
-                mUserLifecycleListeners.get(i).onUserCreated(userInfo);
+                mUserLifecycleListeners.get(i).onUserCreated(userInfo, token);
             }
         }
 
@@ -3868,7 +3885,7 @@
      * @hide
      */
     @Override
-    public UserInfo createRestrictedProfileWithThrow(String name, int parentUserId) {
+    public UserInfo createRestrictedProfileWithThrow(@Nullable String name, int parentUserId) {
         checkManageOrCreateUsersPermission("setupRestrictedProfile");
         final UserInfo user = createProfileForUserWithThrow(
                 name, UserManager.USER_TYPE_FULL_RESTRICTED, 0, parentUserId, null);
@@ -5367,10 +5384,10 @@
 
         @Override
         public UserInfo createUserEvenWhenDisallowed(String name, @NonNull String userType,
-                @UserInfoFlag int flags, String[] disallowedPackages)
+                @UserInfoFlag int flags, String[] disallowedPackages, @Nullable Object token)
                 throws UserManager.CheckedUserOperationException {
             return createUserInternalUnchecked(name, userType, flags,
-                    UserHandle.USER_NULL, /* preCreated= */ false, disallowedPackages);
+                    UserHandle.USER_NULL, /* preCreated= */ false, disallowedPackages, token);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 44a2187..e3ccb75 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -1277,12 +1277,7 @@
                     newFlags |= (flags & PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT);
 
                     // If we are allowlisting the permission, update the exempt flag before grant.
-                    // If the permission can't be allowlisted by an installer, skip it here because
-                    // this is where the platform takes the role of the installer for exempting
-                    // preinstalled apps.
-                    if (whitelistRestrictedPermissions && pm.isPermissionRestricted(permission)
-                            && !pm.getPermissionInfo(permission).isInstallerExemptIgnored()) {
-
+                    if (whitelistRestrictedPermissions && pm.isPermissionRestricted(permission)) {
                         pm.updatePermissionFlags(permission, pkg,
                                 PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT,
                                 PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT, user);
diff --git a/services/core/java/com/android/server/pm/permission/OWNERS b/services/core/java/com/android/server/pm/permission/OWNERS
index e05ef48..8c1a90c 100644
--- a/services/core/java/com/android/server/pm/permission/OWNERS
+++ b/services/core/java/com/android/server/pm/permission/OWNERS
@@ -1,9 +1,7 @@
-zhanghai@google.com
+include platform/frameworks/base:/core/java/android/permission/OWNERS
+
 per-file DefaultPermissionGrantPolicy.java = hackbod@android.com
 per-file DefaultPermissionGrantPolicy.java = jsharkey@android.com
-per-file DefaultPermissionGrantPolicy.java = svetoslavganov@google.com
 per-file DefaultPermissionGrantPolicy.java = toddke@google.com
 per-file DefaultPermissionGrantPolicy.java = yamasani@google.com
 per-file DefaultPermissionGrantPolicy.java = patb@google.com
-per-file DefaultPermissionGrantPolicy.java = eugenesusla@google.com
-per-file DefaultPermissionGrantPolicy.java = zhanghai@google.com
diff --git a/services/core/java/com/android/server/pm/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java
index 32bee58..ac50f29 100644
--- a/services/core/java/com/android/server/pm/permission/Permission.java
+++ b/services/core/java/com/android/server/pm/permission/Permission.java
@@ -239,10 +239,6 @@
         return (mPermissionInfo.flags & PermissionInfo.FLAG_IMMUTABLY_RESTRICTED) != 0;
     }
 
-    public boolean isInstallerExemptIgnored() {
-        return (mPermissionInfo.flags & PermissionInfo.FLAG_INSTALLER_EXEMPT_IGNORED) != 0;
-    }
-
     public boolean isSignature() {
         return (mPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
                 == PermissionInfo.PROTECTION_SIGNATURE;
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 7a936ec..2dfb6ff 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -24,14 +24,12 @@
 import static android.content.pm.ApplicationInfo.AUTO_REVOKE_DISALLOWED;
 import static android.content.pm.ApplicationInfo.AUTO_REVOKE_DISCOURAGED;
 import static android.content.pm.PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_ALLOWLIST_ROLE;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
@@ -771,10 +769,6 @@
 
             isRuntimePermission = bp.isRuntime();
 
-            if (bp.isInstallerExemptIgnored()) {
-                flagValues &= ~FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
-            }
-
             final UidPermissionState uidState = getUidStateLocked(pkg, userId);
             if (uidState == null) {
                 Slog.e(TAG, "Missing permissions state for " + packageName + " and user " + userId);
@@ -1018,8 +1012,7 @@
         Preconditions.checkFlagsArgument(flags,
                 PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
                         | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
-                        | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER
-                        | PackageManager.FLAG_PERMISSION_ALLOWLIST_ROLE);
+                        | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
         Preconditions.checkArgumentNonNegative(userId, null);
 
         if (UserHandle.getCallingUserId() != userId) {
@@ -1043,9 +1036,9 @@
         final boolean isCallerInstallerOnRecord =
                 mPackageManagerInt.isCallerInstallerOfRecord(pkg, callingUid);
 
-        if ((flags & (PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
-                | PackageManager.FLAG_PERMISSION_ALLOWLIST_ROLE)) != 0 && !isCallerPrivileged) {
-            throw new SecurityException("Querying system or role allowlist requires "
+        if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) != 0
+                && !isCallerPrivileged) {
+            throw new SecurityException("Querying system allowlist requires "
                     + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
         }
 
@@ -1087,9 +1080,6 @@
             if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER) != 0) {
                 queryFlags |= FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
             }
-            if ((flags & PackageManager.FLAG_PERMISSION_ALLOWLIST_ROLE) != 0) {
-                queryFlags |=  FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
-            }
 
             ArrayList<String> allowlistedPermissions = null;
 
@@ -1182,8 +1172,7 @@
         Preconditions.checkFlagsArgument(flags,
                 PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
                         | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
-                        | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER
-                        | PackageManager.FLAG_PERMISSION_ALLOWLIST_ROLE);
+                        | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
         Preconditions.checkArgument(Integer.bitCount(flags) == 1);
         Preconditions.checkArgumentNonNegative(userId, null);
 
@@ -1209,10 +1198,8 @@
         final boolean isCallerInstallerOnRecord =
                 mPackageManagerInt.isCallerInstallerOfRecord(pkg, callingUid);
 
-        if ((flags & (PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
-                | PackageManager.FLAG_PERMISSION_ALLOWLIST_ROLE)) != 0
-                && !isCallerPrivileged) {
-            throw new SecurityException("Modifying system or role allowlist requires "
+        if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) != 0 && !isCallerPrivileged) {
+            throw new SecurityException("Modifying system allowlist requires "
                     + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
         }
 
@@ -3718,15 +3705,6 @@
                         }
                     }
                     break;
-                    case FLAG_PERMISSION_ALLOWLIST_ROLE: {
-                        mask |= FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
-                        if (permissions != null && permissions.contains(permissionName)) {
-                            newFlags |= FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
-                        } else {
-                            newFlags &= ~FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
-                        }
-                    }
-                    break;
                 }
             }
 
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java
index 080de73..bf2b3c7 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java
@@ -42,6 +42,8 @@
     private static final Pattern DOMAIN_NAME_WITH_WILDCARD =
             Pattern.compile("(\\*\\.)?" + Patterns.DOMAIN_NAME.pattern());
 
+    private static final int MAX_DOMAINS_BYTE_SIZE = 1024 * 1024;
+
     @NonNull
     private final PlatformCompat mPlatformCompat;
 
@@ -71,7 +73,7 @@
      *     <li>- Only IntentFilter.SCHEME_HTTP and/or IntentFilter.SCHEME_HTTPS,
      *           with no other schemes</li>
      * </ul>
-     *
+     * <p>
      * On prior versions of Android, Intent.CATEGORY_BROWSABLE was not a requirement, other
      * schemes were allowed, and setting autoVerify to true in any intent filter would implicitly
      * pretend that all intent filters were set to autoVerify="true".
@@ -82,42 +84,48 @@
 
     @NonNull
     public ArraySet<String> collectAllWebDomains(@NonNull AndroidPackage pkg) {
-        return collectDomains(pkg, false);
+        return collectDomains(pkg, false /* checkAutoVerify */, true /* valid */);
     }
 
     /**
-     * Effectively {@link #collectAllWebDomains(AndroidPackage)}, but requires
-     * {@link IntentFilter#getAutoVerify()} == true.
+     * Effectively {@link #collectAllWebDomains(AndroidPackage)}, but requires {@link
+     * IntentFilter#getAutoVerify()} == true.
      */
     @NonNull
-    public ArraySet<String> collectAutoVerifyDomains(@NonNull AndroidPackage pkg) {
-        return collectDomains(pkg, true);
+    public ArraySet<String> collectValidAutoVerifyDomains(@NonNull AndroidPackage pkg) {
+        return collectDomains(pkg, true /* checkAutoVerify */, true /* valid */);
+    }
+
+    /**
+     * Returns all the domains that are configured to be auto verified, but aren't actually valid
+     * HTTP domains, per {@link #DOMAIN_NAME_WITH_WILDCARD}.
+     */
+    @NonNull
+    public ArraySet<String> collectInvalidAutoVerifyDomains(@NonNull AndroidPackage pkg) {
+        return collectDomains(pkg, true /* checkAutoVerify */, false /* valid */);
     }
 
     @NonNull
     private ArraySet<String> collectDomains(@NonNull AndroidPackage pkg,
-            boolean checkAutoVerify) {
+            boolean checkAutoVerify, boolean valid) {
         boolean restrictDomains =
                 DomainVerificationUtils.isChangeEnabled(mPlatformCompat, pkg, RESTRICT_DOMAINS);
 
-        ArraySet<String> domains = new ArraySet<>();
-
         if (restrictDomains) {
-            collectDomains(domains, pkg, checkAutoVerify);
+            return collectDomainsInternal(pkg, checkAutoVerify, valid);
         } else {
-            collectDomainsLegacy(domains, pkg, checkAutoVerify);
+            return collectDomainsLegacy(pkg, checkAutoVerify, valid);
         }
-
-        return domains;
     }
 
-    /** @see #RESTRICT_DOMAINS */
-    private void collectDomainsLegacy(@NonNull Set<String> domains,
-            @NonNull AndroidPackage pkg, boolean checkAutoVerify) {
+    /**
+     * @see #RESTRICT_DOMAINS
+     */
+    private ArraySet<String> collectDomainsLegacy(@NonNull AndroidPackage pkg,
+            boolean checkAutoVerify, boolean valid) {
         if (!checkAutoVerify) {
             // Per-domain user selection state doesn't have a V1 equivalent on S, so just use V2
-            collectDomains(domains, pkg, false);
-            return;
+            return collectDomainsInternal(pkg, false /* checkAutoVerify */, true /* valid */);
         }
 
         List<ParsedActivity> activities = pkg.getActivities();
@@ -140,39 +148,54 @@
             }
 
             if (!needsAutoVerify) {
-                return;
+                return new ArraySet<>();
             }
         }
 
-        for (int activityIndex = 0; activityIndex < activitiesSize; activityIndex++) {
+        ArraySet<String> domains = new ArraySet<>();
+        int totalSize = 0;
+        boolean underMaxSize = true;
+        for (int activityIndex = 0; activityIndex < activitiesSize && underMaxSize;
+                activityIndex++) {
             ParsedActivity activity = activities.get(activityIndex);
             List<ParsedIntentInfo> intents = activity.getIntents();
             int intentsSize = intents.size();
-            for (int intentIndex = 0; intentIndex < intentsSize; intentIndex++) {
+            for (int intentIndex = 0; intentIndex < intentsSize && underMaxSize; intentIndex++) {
                 ParsedIntentInfo intent = intents.get(intentIndex);
                 if (intent.handlesWebUris(false)) {
                     int authorityCount = intent.countDataAuthorities();
                     for (int index = 0; index < authorityCount; index++) {
                         String host = intent.getDataAuthority(index).getHost();
-                        if (isValidHost(host)) {
+                        if (isValidHost(host) == valid) {
+                            totalSize += byteSizeOf(host);
+                            underMaxSize = totalSize < MAX_DOMAINS_BYTE_SIZE;
                             domains.add(host);
                         }
                     }
                 }
             }
         }
+
+        return domains;
     }
 
-    /** @see #RESTRICT_DOMAINS */
-    private void collectDomains(@NonNull Set<String> domains,
-            @NonNull AndroidPackage pkg, boolean checkAutoVerify) {
+    /**
+     * @see #RESTRICT_DOMAINS
+     */
+    private ArraySet<String> collectDomainsInternal(@NonNull AndroidPackage pkg,
+            boolean checkAutoVerify, boolean valid) {
+        ArraySet<String> domains = new ArraySet<>();
+        int totalSize = 0;
+        boolean underMaxSize = true;
+
         List<ParsedActivity> activities = pkg.getActivities();
         int activitiesSize = activities.size();
-        for (int activityIndex = 0; activityIndex < activitiesSize; activityIndex++) {
+        for (int activityIndex = 0; activityIndex < activitiesSize && underMaxSize;
+                activityIndex++) {
             ParsedActivity activity = activities.get(activityIndex);
             List<ParsedIntentInfo> intents = activity.getIntents();
             int intentsSize = intents.size();
-            for (int intentIndex = 0; intentIndex < intentsSize; intentIndex++) {
+            for (int intentIndex = 0; intentIndex < intentsSize && underMaxSize; intentIndex++) {
                 ParsedIntentInfo intent = intents.get(intentIndex);
                 if (checkAutoVerify && !intent.getAutoVerify()) {
                     continue;
@@ -198,14 +221,27 @@
                 //  app developer by declaring a separate intent-filter. This may not be worth
                 //  fixing.
                 int authorityCount = intent.countDataAuthorities();
-                for (int index = 0; index < authorityCount; index++) {
+                for (int index = 0; index < authorityCount && underMaxSize; index++) {
                     String host = intent.getDataAuthority(index).getHost();
-                    if (isValidHost(host)) {
+                    if (isValidHost(host) == valid) {
+                        totalSize += byteSizeOf(host);
+                        underMaxSize = totalSize < MAX_DOMAINS_BYTE_SIZE;
                         domains.add(host);
                     }
                 }
             }
         }
+
+        return domains;
+    }
+
+    /**
+     * Ballpark the size of domains to avoid a ridiculous amount of domains that could slow
+     * down client-server communication.
+     */
+    private int byteSizeOf(String string) {
+        // Use the same method from core for the data objects so that restrictions are consistent
+        return android.content.pm.verify.domain.DomainVerificationUtils.estimatedByteSizeOf(string);
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
index b3108c5..c9067a3 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
@@ -107,7 +107,7 @@
         reusedMap.clear();
         reusedMap.putAll(pkgState.getStateMap());
 
-        ArraySet<String> declaredDomains = mCollector.collectAutoVerifyDomains(pkg);
+        ArraySet<String> declaredDomains = mCollector.collectValidAutoVerifyDomains(pkg);
         int declaredSize = declaredDomains.size();
         for (int declaredIndex = 0; declaredIndex < declaredSize; declaredIndex++) {
             String domain = declaredDomains.valueAt(declaredIndex);
@@ -132,6 +132,17 @@
             }
 
             writer.increaseIndent();
+            final ArraySet<String> invalidDomains = mCollector.collectInvalidAutoVerifyDomains(pkg);
+            if (!invalidDomains.isEmpty()) {
+                writer.println("Invalid autoVerify domains:");
+                writer.increaseIndent();
+                int size = invalidDomains.size();
+                for (int index = 0; index < size; index++) {
+                    writer.println(invalidDomains.valueAt(index));
+                }
+                writer.decreaseIndent();
+            }
+
             writer.println("Domain verification state:");
             writer.increaseIndent();
             int stateSize = reusedMap.size();
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationEnforcer.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationEnforcer.java
index 275dd053..ed37fa0 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationEnforcer.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationEnforcer.java
@@ -185,6 +185,29 @@
         return !mCallback.filterAppAccess(packageName, callingUid, targetUserId);
     }
 
+    /**
+     * Querying for the owners of a domain. Because this API cannot filter the returned list of
+     * packages, enforces {@link android.Manifest.permission.QUERY_ALL_PACKAGES}, but also enforces
+     * {@link android.Manifest.permission.INTERACT_ACROSS_USERS} because each user has a different
+     * state.
+     */
+    public void assertOwnerQuerent(int callingUid, @UserIdInt int callingUserId,
+            @UserIdInt int targetUserId) {
+        final int callingPid = Binder.getCallingPid();
+        if (callingUserId != targetUserId) {
+            mContext.enforcePermission(android.Manifest.permission.INTERACT_ACROSS_USERS,
+                    callingPid, callingUid, "Caller is not allowed to query other users");
+        }
+
+        mContext.enforcePermission(android.Manifest.permission.QUERY_ALL_PACKAGES,
+                callingPid, callingUid, "Caller " + callingUid + " does not hold "
+                        + android.Manifest.permission.QUERY_ALL_PACKAGES);
+
+        mContext.enforcePermission(
+                android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION,
+                callingPid, callingUid, "Caller is not allowed to query user selections");
+    }
+
     public interface Callback {
         /**
          * @return true if access to the given package should be filtered and the method failed as
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
index b6ea901..a68b3da 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
@@ -310,7 +310,8 @@
      */
     @ApprovalLevel
     int approvalLevelForDomain(@NonNull PackageSetting pkgSetting, @NonNull Intent intent,
-            @UserIdInt int userId);
+            @NonNull List<ResolveInfo> candidates,
+            @PackageManager.ResolveInfoFlags int resolveInfoFlags, @UserIdInt int userId);
 
     /**
      * @return the domain verification set ID for the given package, or null if the ID is
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerStub.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerStub.java
index 8aa6337..6f28107 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerStub.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerStub.java
@@ -20,13 +20,14 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.verify.domain.DomainOwner;
+import android.content.pm.verify.domain.DomainSet;
+import android.content.pm.verify.domain.DomainVerificationInfo;
 import android.content.pm.verify.domain.DomainVerificationManager.InvalidDomainSetException;
 import android.content.pm.verify.domain.DomainVerificationManagerImpl;
-import android.content.pm.verify.domain.DomainVerificationInfo;
 import android.content.pm.verify.domain.DomainVerificationUserSelection;
 import android.content.pm.verify.domain.IDomainVerificationManager;
 import android.os.ServiceSpecificException;
-import android.util.ArraySet;
 
 import java.util.List;
 import java.util.UUID;
@@ -61,11 +62,11 @@
     }
 
     @Override
-    public void setDomainVerificationStatus(String domainSetId, List<String> domains,
+    public void setDomainVerificationStatus(String domainSetId, @NonNull DomainSet domainSet,
             int state) {
         try {
             mService.setDomainVerificationStatus(UUID.fromString(domainSetId),
-                            new ArraySet<>(domains), state);
+                    domainSet.getDomains(), state);
         } catch (Exception e) {
             throw rethrow(e);
         }
@@ -82,11 +83,11 @@
     }
 
     @Override
-    public void setDomainVerificationUserSelection(String domainSetId, List<String> domains,
+    public void setDomainVerificationUserSelection(String domainSetId, @NonNull DomainSet domainSet,
             boolean enabled, @UserIdInt int userId) {
         try {
             mService.setDomainVerificationUserSelection(UUID.fromString(domainSetId),
-                            new ArraySet<>(domains), enabled, userId);
+                    domainSet.getDomains(), enabled, userId);
         } catch (Exception e) {
             throw rethrow(e);
         }
@@ -103,6 +104,17 @@
         }
     }
 
+    @Nullable
+    @Override
+    public List<DomainOwner> getOwnersForDomain(@NonNull String domain,
+            @UserIdInt int userId) {
+        try {
+            return mService.getOwnersForDomain(domain, userId);
+        } catch (Exception e) {
+            throw rethrow(e);
+        }
+    }
+
     private RuntimeException rethrow(Exception exception) throws RuntimeException {
         if (exception instanceof InvalidDomainSetException) {
             int packedErrorCode = DomainVerificationManagerImpl.ERROR_INVALID_DOMAIN_SET;
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
index 8e5aead..dbd7f96 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
@@ -17,6 +17,7 @@
 package com.android.server.pm.verify.domain;
 
 import static java.util.Collections.emptyList;
+import static java.util.Collections.emptySet;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -30,6 +31,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.pm.parsing.component.ParsedActivity;
+import android.content.pm.verify.domain.DomainOwner;
 import android.content.pm.verify.domain.DomainVerificationInfo;
 import android.content.pm.verify.domain.DomainVerificationManager;
 import android.content.pm.verify.domain.DomainVerificationState;
@@ -254,7 +256,7 @@
             Map<String, Integer> hostToStateMap = new ArrayMap<>(pkgState.getStateMap());
 
             // TODO(b/159952358): Should the domain list be cached?
-            ArraySet<String> domains = mCollector.collectAutoVerifyDomains(pkg);
+            ArraySet<String> domains = mCollector.collectValidAutoVerifyDomains(pkg);
             if (domains.isEmpty()) {
                 return null;
             }
@@ -291,6 +293,8 @@
             throws InvalidDomainSetException, NameNotFoundException {
         mEnforcer.assertApprovedVerifier(callingUid, mProxy);
         synchronized (mLock) {
+            List<String> verifiedDomains = new ArrayList<>();
+
             DomainVerificationPkgState pkgState = getAndValidateAttachedLocked(domainSetId, domains,
                     true /* forAutoVerify */, callingUid, null /* userId */);
             ArrayMap<String, Integer> stateMap = pkgState.getStateMap();
@@ -301,8 +305,17 @@
                     continue;
                 }
 
+                if (DomainVerificationManager.isStateVerified(state)) {
+                    verifiedDomains.add(domain);
+                }
+
                 stateMap.put(domain, state);
             }
+
+            int size = verifiedDomains.size();
+            for (int index = 0; index < size; index++) {
+                removeUserSelectionsForDomain(verifiedDomains.get(index));
+            }
         }
 
         mConnection.scheduleWriteSettings();
@@ -341,7 +354,8 @@
 
                     validDomains.clear();
 
-                    ArraySet<String> autoVerifyDomains = mCollector.collectAutoVerifyDomains(pkg);
+                    ArraySet<String> autoVerifyDomains =
+                            mCollector.collectValidAutoVerifyDomains(pkg);
                     if (domains == null) {
                         validDomains.addAll(autoVerifyDomains);
                     } else {
@@ -366,9 +380,9 @@
 
                 AndroidPackage pkg = pkgSetting.getPkg();
                 if (domains == null) {
-                    domains = mCollector.collectAutoVerifyDomains(pkg);
+                    domains = mCollector.collectValidAutoVerifyDomains(pkg);
                 } else {
-                    domains.retainAll(mCollector.collectAutoVerifyDomains(pkg));
+                    domains.retainAll(mCollector.collectValidAutoVerifyDomains(pkg));
                 }
 
                 setDomainVerificationStatusInternal(pkgState, state, domains);
@@ -387,6 +401,20 @@
         }
     }
 
+    private void removeUserSelectionsForDomain(@NonNull String domain) {
+        synchronized (mLock) {
+            final int size = mAttachedPkgStates.size();
+            for (int index = 0; index < size; index++) {
+                DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index);
+                SparseArray<DomainVerificationUserState> array = pkgState.getUserSelectionStates();
+                int arraySize = array.size();
+                for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) {
+                    array.valueAt(arrayIndex).removeHost(domain);
+                }
+            }
+        }
+    }
+
     @Override
     public void setDomainVerificationLinkHandlingAllowed(@NonNull String packageName,
             boolean allowed) throws NameNotFoundException {
@@ -470,19 +498,59 @@
                         InvalidDomainSetException.REASON_ID_INVALID);
             }
 
+            DomainVerificationPkgState pkgState = getAndValidateAttachedLocked(domainSetId, domains,
+                    false /* forAutoVerify */, callingUid, userId);
+            DomainVerificationUserState userState = pkgState.getOrCreateUserSelectionState(userId);
+
+            // Disable other packages if approving this one. Note that this check is only done for
+            // enabling. This allows an escape hatch in case multiple packages somehow get selected.
+            // They can be disabled without blocking in a circular dependency.
             if (enabled) {
+                // Cache the approved packages from the 1st pass because the search is expensive
+                ArrayMap<String, List<String>> domainToApprovedPackages = new ArrayMap<>();
+
                 for (String domain : domains) {
-                    if (!getApprovedPackages(domain, userId, APPROVAL_LEVEL_LEGACY_ALWAYS + 1,
-                            mConnection::getPackageSettingLocked).first.isEmpty()) {
+                    if (userState.getEnabledHosts().contains(domain)) {
+                        continue;
+                    }
+
+                    Pair<List<String>, Integer> packagesToLevel = getApprovedPackages(domain,
+                            userId, APPROVAL_LEVEL_NONE + 1, mConnection::getPackageSettingLocked);
+                    int highestApproval = packagesToLevel.second;
+                    if (highestApproval > APPROVAL_LEVEL_SELECTION) {
                         throw new InvalidDomainSetException(domainSetId, null,
                                 InvalidDomainSetException.REASON_UNABLE_TO_APPROVE);
                     }
+
+                    domainToApprovedPackages.put(domain, packagesToLevel.first);
+                }
+
+                // The removal for other packages must be done in a 2nd pass after it's determined
+                // that no higher priority owners exist for all of the domains in the set.
+                int mapSize = domainToApprovedPackages.size();
+                for (int mapIndex = 0; mapIndex < mapSize; mapIndex++) {
+                    String domain = domainToApprovedPackages.keyAt(mapIndex);
+                    List<String> approvedPackages = domainToApprovedPackages.valueAt(mapIndex);
+                    int approvedSize = approvedPackages.size();
+                    for (int approvedIndex = 0; approvedIndex < approvedSize; approvedIndex++) {
+                        String approvedPackage = approvedPackages.get(approvedIndex);
+                        DomainVerificationPkgState approvedPkgState =
+                                mAttachedPkgStates.get(approvedPackage);
+                        if (approvedPkgState == null) {
+                            continue;
+                        }
+
+                        DomainVerificationUserState approvedUserState =
+                                approvedPkgState.getUserSelectionState(userId);
+                        if (approvedUserState == null) {
+                            continue;
+                        }
+
+                        approvedUserState.removeHost(domain);
+                    }
                 }
             }
 
-            DomainVerificationPkgState pkgState = getAndValidateAttachedLocked(domainSetId, domains,
-                    false /* forAutoVerify */, callingUid, userId);
-            DomainVerificationUserState userState = pkgState.getOrCreateUserSelectionState(userId);
             if (enabled) {
                 userState.addHosts(domains);
             } else {
@@ -600,32 +668,113 @@
                 throw DomainVerificationUtils.throwPackageUnavailable(packageName);
             }
 
-            ArrayMap<String, Boolean> hostToUserSelectionMap = new ArrayMap<>();
+            ArraySet<String> webDomains = mCollector.collectAllWebDomains(pkg);
+            int webDomainsSize = webDomains.size();
 
-            ArraySet<String> domains = mCollector.collectAllWebDomains(pkg);
-            int domainsSize = domains.size();
-            for (int index = 0; index < domainsSize; index++) {
-                hostToUserSelectionMap.put(domains.valueAt(index), false);
-            }
-
+            Map<String, Integer> domains = new ArrayMap<>(webDomainsSize);
+            ArrayMap<String, Integer> stateMap = pkgState.getStateMap();
             DomainVerificationUserState userState = pkgState.getUserSelectionState(userId);
-            boolean linkHandlingAllowed = true;
-            if (userState != null) {
-                linkHandlingAllowed = userState.isLinkHandlingAllowed();
-                ArraySet<String> enabledHosts = userState.getEnabledHosts();
-                int hostsSize = enabledHosts.size();
-                for (int index = 0; index < hostsSize; index++) {
-                    hostToUserSelectionMap.put(enabledHosts.valueAt(index), true);
+            Set<String> enabledHosts = userState == null ? emptySet() : userState.getEnabledHosts();
+
+            for (int index = 0; index < webDomainsSize; index++) {
+                String host = webDomains.valueAt(index);
+                Integer state = stateMap.get(host);
+
+                int domainState;
+                if (state != null && DomainVerificationManager.isStateVerified(state)) {
+                    domainState = DomainVerificationUserSelection.DOMAIN_STATE_VERIFIED;
+                } else if (enabledHosts.contains(host)) {
+                    domainState = DomainVerificationUserSelection.DOMAIN_STATE_SELECTED;
+                } else {
+                    domainState = DomainVerificationUserSelection.DOMAIN_STATE_NONE;
                 }
+
+                domains.put(host, domainState);
             }
 
+            boolean linkHandlingAllowed = userState == null || userState.isLinkHandlingAllowed();
+
             return new DomainVerificationUserSelection(pkgState.getId(), packageName,
-                    UserHandle.of(userId), linkHandlingAllowed, hostToUserSelectionMap);
+                    UserHandle.of(userId), linkHandlingAllowed, domains);
         }
     }
 
     @NonNull
     @Override
+    public List<DomainOwner> getOwnersForDomain(@NonNull String domain) {
+        return getOwnersForDomain(domain, mConnection.getCallingUserId());
+    }
+
+    public List<DomainOwner> getOwnersForDomain(@NonNull String domain, @UserIdInt int userId) {
+        mEnforcer.assertOwnerQuerent(mConnection.getCallingUid(), mConnection.getCallingUserId(),
+                userId);
+
+        SparseArray<List<String>> levelToPackages = new SparseArray<>();
+
+        // First, collect the raw approval level values
+        synchronized (mLock) {
+            final int size = mAttachedPkgStates.size();
+            for (int index = 0; index < size; index++) {
+                DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index);
+                String packageName = pkgState.getPackageName();
+                PackageSetting pkgSetting = mConnection.getPackageSettingLocked(packageName);
+                if (pkgSetting == null) {
+                    continue;
+                }
+
+                int level = approvalLevelForDomain(pkgSetting, domain, userId, domain);
+                if (level <= APPROVAL_LEVEL_NONE) {
+                    continue;
+                }
+                List<String> list = levelToPackages.get(level);
+                if (list == null) {
+                    list = new ArrayList<>();
+                    levelToPackages.put(level, list);
+                }
+                list.add(packageName);
+            }
+        }
+
+        final int size = levelToPackages.size();
+        if (size == 0) {
+            return emptyList();
+        }
+
+        // Then sort them ascending by first installed time, with package name as the tie breaker
+        for (int index = 0; index < size; index++) {
+            levelToPackages.valueAt(index).sort((first, second) -> {
+                PackageSetting firstPkgSetting = mConnection.getPackageSettingLocked(first);
+                PackageSetting secondPkgSetting = mConnection.getPackageSettingLocked(second);
+
+                long firstInstallTime =
+                        firstPkgSetting == null ? -1L : firstPkgSetting.getFirstInstallTime();
+                long secondInstallTime =
+                        secondPkgSetting == null ? -1L : secondPkgSetting.getFirstInstallTime();
+
+                if (firstInstallTime != secondInstallTime) {
+                    return (int) (firstInstallTime - secondInstallTime);
+                }
+
+                return first.compareToIgnoreCase(second);
+            });
+        }
+
+        List<DomainOwner> owners = new ArrayList<>();
+        for (int index = 0; index < size; index++) {
+            int level = levelToPackages.keyAt(index);
+            boolean overrideable = level <= APPROVAL_LEVEL_SELECTION;
+            List<String> packages = levelToPackages.valueAt(index);
+            int packagesSize = packages.size();
+            for (int packageIndex = 0; packageIndex < packagesSize; packageIndex++) {
+                owners.add(new DomainOwner(packages.get(packageIndex), overrideable));
+            }
+        }
+
+        return owners;
+    }
+
+    @NonNull
+    @Override
     public UUID generateNewId() {
         // TODO(b/159952358): Domain set ID collisions
         return UUID.randomUUID();
@@ -634,7 +783,7 @@
     @Override
     public void migrateState(@NonNull PackageSetting oldPkgSetting,
             @NonNull PackageSetting newPkgSetting) {
-        String pkgName = newPkgSetting.name;
+        String pkgName = newPkgSetting.getName();
         boolean sendBroadcast;
 
         synchronized (mLock) {
@@ -663,7 +812,8 @@
             }
 
             ArrayMap<String, Integer> oldStateMap = oldPkgState.getStateMap();
-            ArraySet<String> newAutoVerifyDomains = mCollector.collectAutoVerifyDomains(newPkg);
+            ArraySet<String> newAutoVerifyDomains =
+                    mCollector.collectValidAutoVerifyDomains(newPkg);
             int newDomainsSize = newAutoVerifyDomains.size();
 
             for (int newDomainsIndex = 0; newDomainsIndex < newDomainsSize; newDomainsIndex++) {
@@ -692,7 +842,7 @@
                     oldPkgState.getUserSelectionStates();
             int oldUserStatesSize = oldUserStates.size();
             if (oldUserStatesSize > 0) {
-                ArraySet<String> newWebDomains = mCollector.collectAutoVerifyDomains(newPkg);
+                ArraySet<String> newWebDomains = mCollector.collectValidAutoVerifyDomains(newPkg);
                 for (int oldUserStatesIndex = 0; oldUserStatesIndex < oldUserStatesSize;
                         oldUserStatesIndex++) {
                     int userId = oldUserStates.keyAt(oldUserStatesIndex);
@@ -730,7 +880,7 @@
         //  gains or loses all domains.
 
         UUID domainSetId = newPkgSetting.getDomainSetId();
-        String pkgName = newPkgSetting.name;
+        String pkgName = newPkgSetting.getName();
 
         boolean sendBroadcast = true;
 
@@ -745,7 +895,7 @@
         }
 
         AndroidPackage pkg = newPkgSetting.getPkg();
-        ArraySet<String> domains = mCollector.collectAutoVerifyDomains(pkg);
+        ArraySet<String> domains = mCollector.collectValidAutoVerifyDomains(pkg);
         boolean hasAutoVerifyDomains = !domains.isEmpty();
         boolean isPendingOrRestored = pkgState != null;
         if (isPendingOrRestored) {
@@ -1009,7 +1159,7 @@
         }
         AndroidPackage pkg = pkgSetting.getPkg();
         ArraySet<String> declaredDomains = forAutoVerify
-                ? mCollector.collectAutoVerifyDomains(pkg)
+                ? mCollector.collectValidAutoVerifyDomains(pkg)
                 : mCollector.collectAllWebDomains(pkg);
 
         if (domains.retainAll(declaredDomains)) {
@@ -1141,7 +1291,7 @@
             }
         }
 
-        applyImmutableState(pkgState, mCollector.collectAutoVerifyDomains(pkg));
+        applyImmutableState(pkgState, mCollector.collectValidAutoVerifyDomains(pkg));
     }
 
     @Override
@@ -1346,9 +1496,11 @@
 
     @Override
     public int approvalLevelForDomain(@NonNull PackageSetting pkgSetting, @NonNull Intent intent,
-            @UserIdInt int userId) {
-        String packageName = pkgSetting.name;
-        if (!DomainVerificationUtils.isDomainVerificationIntent(intent)) {
+            @NonNull List<ResolveInfo> candidates,
+            @PackageManager.ResolveInfoFlags int resolveInfoFlags, @UserIdInt int userId) {
+        String packageName = pkgSetting.getName();
+        if (!DomainVerificationUtils.isDomainVerificationIntent(intent, candidates,
+                resolveInfoFlags)) {
             if (DEBUG_APPROVAL) {
                 debugApproval(packageName, intent, userId, false, "not valid intent");
             }
@@ -1364,7 +1516,7 @@
      */
     private int approvalLevelForDomain(@NonNull PackageSetting pkgSetting, @NonNull String host,
             @UserIdInt int userId, @NonNull Object debugObject) {
-        String packageName = pkgSetting.name;
+        String packageName = pkgSetting.getName();
         final AndroidPackage pkg = pkgSetting.getPkg();
 
         // Should never be null, but if it is, skip this and assume that v2 is enabled
@@ -1409,7 +1561,7 @@
                 // To allow an instant app to immediately open domains after being installed by the
                 // user, auto approve them for any declared autoVerify domains.
                 if (pkgSetting.getInstantApp(userId)
-                        && mCollector.collectAutoVerifyDomains(pkg).contains(host)) {
+                        && mCollector.collectValidAutoVerifyDomains(pkg).contains(host)) {
                     return APPROVAL_LEVEL_INSTANT_APP;
                 }
             }
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java
index 475d3a8..883bbad 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java
@@ -22,12 +22,17 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
 import android.os.Binder;
 
+import com.android.internal.util.CollectionUtils;
 import com.android.server.compat.PlatformCompat;
 import com.android.server.pm.PackageManagerService;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 
+import java.util.List;
+import java.util.Set;
+
 public final class DomainVerificationUtils {
 
     /**
@@ -40,10 +45,61 @@
         throw new NameNotFoundException("Package " + packageName + " unavailable");
     }
 
-    public static boolean isDomainVerificationIntent(Intent intent) {
-        return intent.isWebIntent()
-                && intent.hasCategory(Intent.CATEGORY_BROWSABLE)
-                && intent.hasCategory(Intent.CATEGORY_DEFAULT);
+    public static boolean isDomainVerificationIntent(Intent intent,
+            @NonNull List<ResolveInfo> candidates,
+            @PackageManager.ResolveInfoFlags int resolveInfoFlags) {
+        if (!intent.isWebIntent()) {
+            return false;
+        }
+
+        Set<String> categories = intent.getCategories();
+        int categoriesSize = CollectionUtils.size(categories);
+        if (categoriesSize > 2) {
+            // Specifying at least one non-app-link category
+            return false;
+        } else if (categoriesSize == 2) {
+            // Check for explicit app link intent with exactly BROWSABLE && DEFAULT
+            return intent.hasCategory(Intent.CATEGORY_DEFAULT)
+                    && intent.hasCategory(Intent.CATEGORY_BROWSABLE);
+        }
+
+            // In cases where at least one browser is resolved and only one non-browser is resolved,
+        // the Intent is coerced into an app links intent, under the assumption the browser can
+        // be skipped if the app is approved at any level for the domain.
+        boolean foundBrowser = false;
+        boolean foundOneApp = false;
+
+        final int candidatesSize = candidates.size();
+        for (int index = 0; index < candidatesSize; index++) {
+            final ResolveInfo info = candidates.get(index);
+            if (info.handleAllWebDataURI) {
+                foundBrowser = true;
+            } else if (foundOneApp) {
+                // Already true, so duplicate app
+                foundOneApp = false;
+                break;
+            } else {
+                foundOneApp = true;
+            }
+        }
+
+        boolean matchDefaultByFlags = (resolveInfoFlags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
+        boolean onlyOneNonBrowser = foundBrowser && foundOneApp;
+
+        // Check if matches (BROWSABLE || none) && DEFAULT
+        if (categoriesSize == 0) {
+            // No categories, run coerce case, matching DEFAULT by flags
+            return onlyOneNonBrowser && matchDefaultByFlags;
+        } else if (intent.hasCategory(Intent.CATEGORY_DEFAULT)) {
+            // Run coerce case, matching by explicit DEFAULT
+            return onlyOneNonBrowser;
+        } else if (intent.hasCategory(Intent.CATEGORY_BROWSABLE)) {
+            // Intent matches BROWSABLE, must match DEFAULT by flags
+            return matchDefaultByFlags;
+        } else {
+            // Otherwise not matching any app link categories
+            return false;
+        }
     }
 
     static boolean isChangeEnabled(PlatformCompat platformCompat, AndroidPackage pkg,
diff --git a/services/core/java/com/android/server/pm/verify/domain/OWNERS b/services/core/java/com/android/server/pm/verify/domain/OWNERS
new file mode 100644
index 0000000..c669112
--- /dev/null
+++ b/services/core/java/com/android/server/pm/verify/domain/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 36137
+
+chiuwinson@google.com
+patb@google.com
+toddke@google.com
\ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationUserState.java b/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationUserState.java
index 2246864..8fbb33a 100644
--- a/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationUserState.java
+++ b/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationUserState.java
@@ -58,6 +58,11 @@
         return this;
     }
 
+    public DomainVerificationUserState removeHost(String host) {
+        mEnabledHosts.remove(host);
+        return this;
+    }
+
     public DomainVerificationUserState removeHosts(@NonNull ArraySet<String> newHosts) {
         mEnabledHosts.removeAll(newHosts);
         return this;
diff --git a/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java b/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java
index a804065..18042af 100644
--- a/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java
+++ b/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java
@@ -16,6 +16,9 @@
 
 package com.android.server.pm.verify.domain.proxy;
 
+import static android.os.PowerWhitelistManager.REASON_DOMAIN_VERIFICATION_V1;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
+
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -238,7 +241,8 @@
         final long allowListTimeout = mConnection.getPowerSaveTempWhitelistAppDuration();
         mConnection.getDeviceIdleInternal().addPowerSaveTempWhitelistApp(Process.myUid(),
                 mVerifierComponent.getPackageName(), allowListTimeout,
-                UserHandle.USER_SYSTEM, true, "domain verification agent");
+                UserHandle.USER_SYSTEM, true, REASON_DOMAIN_VERIFICATION_V1,
+                "domain verification agent");
 
         int size = verifications.size();
         for (int index = 0; index < size; index++) {
@@ -261,7 +265,9 @@
                     .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
 
             final BroadcastOptions options = BroadcastOptions.makeBasic();
-            options.setTemporaryAppWhitelistDuration(allowListTimeout);
+            options.setTemporaryAppAllowlist(allowListTimeout,
+                    TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                    REASON_DOMAIN_VERIFICATION_V1, "");
             mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM, null, options.toBundle());
         }
     }
@@ -270,7 +276,7 @@
     private String buildHostsString(@NonNull AndroidPackage pkg) {
         // The collector itself handles the v1 vs v2 behavior, which is based on targetSdkVersion,
         // not the version of the verification agent on device.
-        ArraySet<String> domains = mCollector.collectAutoVerifyDomains(pkg);
+        ArraySet<String> domains = mCollector.collectValidAutoVerifyDomains(pkg);
 
         // v1 doesn't handle wildcard domains, so transform them here to the root
         StringBuilder builder = new StringBuilder();
diff --git a/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV2.java b/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV2.java
index 1ef06036..2ba17d3 100644
--- a/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV2.java
+++ b/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV2.java
@@ -16,6 +16,9 @@
 
 package com.android.server.pm.verify.domain.proxy;
 
+import static android.os.PowerWhitelistManager.REASON_DOMAIN_VERIFICATION_V2;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.BroadcastOptions;
@@ -69,11 +72,14 @@
 
                 final long allowListTimeout = mConnection.getPowerSaveTempWhitelistAppDuration();
                 final BroadcastOptions options = BroadcastOptions.makeBasic();
-                options.setTemporaryAppWhitelistDuration(allowListTimeout);
+                options.setTemporaryAppAllowlist(allowListTimeout,
+                        TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                        REASON_DOMAIN_VERIFICATION_V2, "");
 
                 mConnection.getDeviceIdleInternal().addPowerSaveTempWhitelistApp(Process.myUid(),
                         mVerifierComponent.getPackageName(), allowListTimeout,
-                        UserHandle.USER_SYSTEM, true, "domain verification agent");
+                        UserHandle.USER_SYSTEM, true, REASON_DOMAIN_VERIFICATION_V2,
+                        "domain verification agent");
 
                 Intent intent = new Intent(Intent.ACTION_DOMAINS_NEED_VERIFICATION)
                         .setComponent(mVerifierComponent)
diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java
new file mode 100644
index 0000000..c965390
--- /dev/null
+++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java
@@ -0,0 +1,151 @@
+/*
+ * 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.annotation.Nullable;
+import android.app.AppOpsManager;
+import android.app.AppOpsManagerInternal;
+import android.location.LocationManagerInternal;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.function.HeptFunction;
+import com.android.internal.util.function.QuadFunction;
+import com.android.server.LocalServices;
+
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * This class defines policy for special behaviors around app ops.
+ */
+public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegate {
+    @NonNull
+    private final Object mLock = new Object();
+
+    /**
+     * The locking policy around the location tags is a bit special. Since we want to
+     * avoid grabbing the lock on every op note we are taking the approach where the
+     * read and write are being done via a thread-safe data structure such that the
+     * lookup/insert are single thread-safe calls. When we update the cached state we
+     * use a lock to ensure the update's lookup and store calls are done atomically,
+     * so multiple writers would not interleave. The tradeoff is we make is that the
+     * concurrent data structure would use boxing/unboxing of integers but this is
+     * preferred to locking.
+     */
+    @GuardedBy("mLock - writes only - see above")
+    @NonNull
+    private final ConcurrentHashMap<Integer, ArrayMap<String, ArraySet<String>>> mLocationTags =
+            new ConcurrentHashMap();
+
+    public AppOpsPolicy() {
+        final LocationManagerInternal locationManagerInternal = LocalServices.getService(
+                LocationManagerInternal.class);
+        locationManagerInternal.setOnProviderLocationTagsChangeListener((providerTagInfo) -> {
+            synchronized (mLock) {
+                final int uid = providerTagInfo.getUid();
+                // We make a copy of the per UID state to limit our mutation to one
+                // operation in the underlying concurrent data structure.
+                ArrayMap<String, ArraySet<String>> uidTags = mLocationTags.get(uid);
+                if (uidTags != null) {
+                    uidTags = new ArrayMap<>(uidTags);
+                }
+
+                final String packageName = providerTagInfo.getPackageName();
+                ArraySet<String> packageTags = (uidTags != null) ? uidTags.get(packageName) : null;
+                if (packageTags != null) {
+                    packageTags = new ArraySet<>(packageTags);
+                }
+
+                final Set<String> providerTags = providerTagInfo.getTags();
+                if (providerTags != null && !providerTags.isEmpty()) {
+                    if (packageTags != null) {
+                        packageTags.clear();
+                        packageTags.addAll(providerTags);
+                    } else {
+                        packageTags = new ArraySet<>(providerTags);
+                    }
+                    if (uidTags == null) {
+                        uidTags = new ArrayMap<>();
+                    }
+                    uidTags.put(packageName, packageTags);
+                    mLocationTags.put(uid, uidTags);
+                } else if (uidTags != null) {
+                    uidTags.remove(packageName);
+                    if (!uidTags.isEmpty()) {
+                        mLocationTags.put(uid, uidTags);
+                    } else {
+                        mLocationTags.remove(uid);
+                    }
+                }
+            }
+        });
+    }
+
+    @Override
+    public int checkOperation(int code, int uid, String packageName, boolean raw,
+            QuadFunction<Integer, Integer, String, Boolean, Integer> superImpl) {
+        return superImpl.apply(code, uid, packageName, raw);
+    }
+
+    @Override
+    public int checkAudioOperation(int code, int usage, int uid, String packageName,
+            QuadFunction<Integer, Integer, Integer, String, Integer> superImpl) {
+        return superImpl.apply(code, usage, uid, packageName);
+    }
+
+    @Override
+    public int noteOperation(int code, int uid, @Nullable String packageName,
+            @Nullable String featureId, boolean shouldCollectAsyncNotedOp, @Nullable String message,
+            boolean shouldCollectMessage, @NonNull HeptFunction<Integer, Integer, String, String,
+                    Boolean, String, Boolean, Integer> superImpl) {
+        if (isHandledOp(code)) {
+            // Only a single lookup from the underlying concurrent data structure
+            final ArrayMap<String, ArraySet<String>> uidTags = mLocationTags.get(uid);
+            if (uidTags != null) {
+                final ArraySet<String> packageTags = uidTags.get(packageName);
+                if (packageTags != null && packageTags.contains(featureId)) {
+                    return superImpl.apply(resolveLocationOp(code), uid, packageName, featureId,
+                            shouldCollectAsyncNotedOp, message, shouldCollectMessage);
+                }
+            }
+        }
+        return superImpl.apply(code, uid, packageName, featureId, shouldCollectAsyncNotedOp,
+                message, shouldCollectMessage);
+    }
+
+    private static boolean isHandledOp(int code) {
+        switch (code) {
+            case AppOpsManager.OP_FINE_LOCATION:
+            case AppOpsManager.OP_COARSE_LOCATION:
+                return true;
+        }
+        return false;
+    }
+
+    private static int resolveLocationOp(int code) {
+        switch (code) {
+            case AppOpsManager.OP_FINE_LOCATION:
+                return AppOpsManager.OP_FINE_LOCATION_SOURCE;
+            case AppOpsManager.OP_COARSE_LOCATION:
+                return AppOpsManager.OP_COARSE_LOCATION_SOURCE;
+        }
+        return code;
+    }
+}
diff --git a/services/core/java/com/android/server/policy/DisplayFoldController.java b/services/core/java/com/android/server/policy/DisplayFoldController.java
index 82fc22c..0e12584 100644
--- a/services/core/java/com/android/server/policy/DisplayFoldController.java
+++ b/services/core/java/com/android/server/policy/DisplayFoldController.java
@@ -74,7 +74,7 @@
         mHandler = handler;
 
         DeviceStateManager deviceStateManager = context.getSystemService(DeviceStateManager.class);
-        deviceStateManager.addDeviceStateListener(new HandlerExecutor(handler),
+        deviceStateManager.registerCallback(new HandlerExecutor(handler),
                 new DeviceStateListener(context));
     }
 
@@ -208,7 +208,7 @@
      * matches the value in the {@link com.android.internal.R.integer.config_foldedDeviceState}
      * resource.
      */
-    private class DeviceStateListener implements DeviceStateManager.DeviceStateListener {
+    private class DeviceStateListener implements DeviceStateManager.DeviceStateCallback {
         private final int[] mFoldedDeviceStates;
 
         DeviceStateListener(Context context) {
@@ -217,7 +217,7 @@
         }
 
         @Override
-        public void onDeviceStateChanged(int deviceState) {
+        public void onStateChanged(int deviceState) {
             boolean folded = false;
             for (int i = 0; i < mFoldedDeviceStates.length; i++) {
                 if (deviceState == mFoldedDeviceStates[i]) {
diff --git a/services/core/java/com/android/server/policy/ModifierShortcutManager.java b/services/core/java/com/android/server/policy/ModifierShortcutManager.java
new file mode 100644
index 0000000..a0771c0
--- /dev/null
+++ b/services/core/java/com/android/server/policy/ModifierShortcutManager.java
@@ -0,0 +1,380 @@
+/*
+ * 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.content.ActivityNotFoundException;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.res.XmlResourceParser;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.LongSparseArray;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+
+import com.android.internal.policy.IShortcutService;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * Manages quick launch shortcuts by:
+ * <li> Keeping the local copy in sync with the database (this is an observer)
+ * <li> Returning a shortcut-matching intent to clients
+ * <li> Returning particular kind of application intent by special key.
+ */
+class ModifierShortcutManager {
+    private static final String TAG = "ShortcutManager";
+
+    private static final String TAG_BOOKMARKS = "bookmarks";
+    private static final String TAG_BOOKMARK = "bookmark";
+
+    private static final String ATTRIBUTE_PACKAGE = "package";
+    private static final String ATTRIBUTE_CLASS = "class";
+    private static final String ATTRIBUTE_SHORTCUT = "shortcut";
+    private static final String ATTRIBUTE_CATEGORY = "category";
+    private static final String ATTRIBUTE_SHIFT = "shift";
+
+    private final SparseArray<ShortcutInfo> mIntentShortcuts = new SparseArray<>();
+    private final SparseArray<ShortcutInfo> mShiftShortcuts = new SparseArray<>();
+
+    private LongSparseArray<IShortcutService> mShortcutKeyServices = new LongSparseArray<>();
+
+    /* Table of Application Launch keys.  Maps from key codes to intent categories.
+     *
+     * These are special keys that are used to launch particular kinds of applications,
+     * such as a web browser.  HID defines nearly a hundred of them in the Consumer (0x0C)
+     * usage page.  We don't support quite that many yet...
+     */
+    static SparseArray<String> sApplicationLaunchKeyCategories;
+    static {
+        sApplicationLaunchKeyCategories = new SparseArray<String>();
+        sApplicationLaunchKeyCategories.append(
+                KeyEvent.KEYCODE_EXPLORER, Intent.CATEGORY_APP_BROWSER);
+        sApplicationLaunchKeyCategories.append(
+                KeyEvent.KEYCODE_ENVELOPE, Intent.CATEGORY_APP_EMAIL);
+        sApplicationLaunchKeyCategories.append(
+                KeyEvent.KEYCODE_CONTACTS, Intent.CATEGORY_APP_CONTACTS);
+        sApplicationLaunchKeyCategories.append(
+                KeyEvent.KEYCODE_CALENDAR, Intent.CATEGORY_APP_CALENDAR);
+        sApplicationLaunchKeyCategories.append(
+                KeyEvent.KEYCODE_MUSIC, Intent.CATEGORY_APP_MUSIC);
+        sApplicationLaunchKeyCategories.append(
+                KeyEvent.KEYCODE_CALCULATOR, Intent.CATEGORY_APP_CALCULATOR);
+    }
+
+    private final Context mContext;
+    private boolean mSearchKeyShortcutPending = false;
+    private boolean mConsumeSearchKeyUp = true;
+
+    ModifierShortcutManager(Context context) {
+        mContext = context;
+        loadShortcuts();
+    }
+
+    /**
+     * Gets the shortcut intent for a given keycode+modifier. Make sure you
+     * strip whatever modifier is used for invoking shortcuts (for example,
+     * if 'Sym+A' should invoke a shortcut on 'A', you should strip the
+     * 'Sym' bit from the modifiers before calling this method.
+     * <p>
+     * This will first try an exact match (with modifiers), and then try a
+     * match without modifiers (primary character on a key).
+     *
+     * @param kcm The key character map of the device on which the key was pressed.
+     * @param keyCode The key code.
+     * @param metaState The meta state, omitting any modifiers that were used
+     * to invoke the shortcut.
+     * @return The intent that matches the shortcut, or null if not found.
+     */
+    private Intent getIntent(KeyCharacterMap kcm, int keyCode, int metaState) {
+        ShortcutInfo shortcut = null;
+
+        // If the Shift key is pressed, then search for the shift shortcuts.
+        boolean isShiftOn = (metaState & KeyEvent.META_SHIFT_ON) == KeyEvent.META_SHIFT_ON;
+        SparseArray<ShortcutInfo> shortcutMap = isShiftOn ? mShiftShortcuts : mIntentShortcuts;
+
+        // First try the exact keycode (with modifiers).
+        int shortcutChar = kcm.get(keyCode, metaState);
+        if (shortcutChar != 0) {
+            shortcut = shortcutMap.get(shortcutChar);
+        }
+
+        // Next try the primary character on that key.
+        if (shortcut == null) {
+            shortcutChar = Character.toLowerCase(kcm.getDisplayLabel(keyCode));
+            if (shortcutChar != 0) {
+                shortcut = shortcutMap.get(shortcutChar);
+            }
+        }
+
+        return (shortcut != null) ? shortcut.intent : null;
+    }
+
+    private void loadShortcuts() {
+        PackageManager packageManager = mContext.getPackageManager();
+        try {
+            XmlResourceParser parser = mContext.getResources().getXml(
+                    com.android.internal.R.xml.bookmarks);
+            XmlUtils.beginDocument(parser, TAG_BOOKMARKS);
+
+            while (true) {
+                XmlUtils.nextElement(parser);
+
+                if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
+                    break;
+                }
+
+                if (!TAG_BOOKMARK.equals(parser.getName())) {
+                    break;
+                }
+
+                String packageName = parser.getAttributeValue(null, ATTRIBUTE_PACKAGE);
+                String className = parser.getAttributeValue(null, ATTRIBUTE_CLASS);
+                String shortcutName = parser.getAttributeValue(null, ATTRIBUTE_SHORTCUT);
+                String categoryName = parser.getAttributeValue(null, ATTRIBUTE_CATEGORY);
+                String shiftName = parser.getAttributeValue(null, ATTRIBUTE_SHIFT);
+
+                if (TextUtils.isEmpty(shortcutName)) {
+                    Log.w(TAG, "Unable to get shortcut for: " + packageName + "/" + className);
+                    continue;
+                }
+
+                final int shortcutChar = shortcutName.charAt(0);
+                final boolean isShiftShortcut = (shiftName != null && shiftName.equals("true"));
+
+                final Intent intent;
+                final String title;
+                if (packageName != null && className != null) {
+                    ActivityInfo info = null;
+                    ComponentName componentName = new ComponentName(packageName, className);
+                    try {
+                        info = packageManager.getActivityInfo(componentName,
+                                PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                                        | PackageManager.MATCH_UNINSTALLED_PACKAGES);
+                    } catch (PackageManager.NameNotFoundException e) {
+                        String[] packages = packageManager.canonicalToCurrentPackageNames(
+                                new String[] { packageName });
+                        componentName = new ComponentName(packages[0], className);
+                        try {
+                            info = packageManager.getActivityInfo(componentName,
+                                    PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                                            | PackageManager.MATCH_UNINSTALLED_PACKAGES);
+                        } catch (PackageManager.NameNotFoundException e1) {
+                            Log.w(TAG, "Unable to add bookmark: " + packageName
+                                    + "/" + className, e);
+                            continue;
+                        }
+                    }
+
+                    intent = new Intent(Intent.ACTION_MAIN);
+                    intent.addCategory(Intent.CATEGORY_LAUNCHER);
+                    intent.setComponent(componentName);
+                    title = info.loadLabel(packageManager).toString();
+                } else if (categoryName != null) {
+                    intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, categoryName);
+                    title = "";
+                } else {
+                    Log.w(TAG, "Unable to add bookmark for shortcut " + shortcutName
+                            + ": missing package/class or category attributes");
+                    continue;
+                }
+
+                ShortcutInfo shortcut = new ShortcutInfo(title, intent);
+                if (isShiftShortcut) {
+                    mShiftShortcuts.put(shortcutChar, shortcut);
+                } else {
+                    mIntentShortcuts.put(shortcutChar, shortcut);
+                }
+            }
+        } catch (XmlPullParserException e) {
+            Log.w(TAG, "Got exception parsing bookmarks.", e);
+        } catch (IOException e) {
+            Log.w(TAG, "Got exception parsing bookmarks.", e);
+        }
+    }
+
+    void registerShortcutKey(long shortcutCode, IShortcutService shortcutService)
+            throws RemoteException {
+        IShortcutService service = mShortcutKeyServices.get(shortcutCode);
+        if (service != null && service.asBinder().pingBinder()) {
+            throw new RemoteException("Key already exists.");
+        }
+
+        mShortcutKeyServices.put(shortcutCode, shortcutService);
+    }
+
+    /**
+     * Handle the shortcut to {@link IShortcutService}
+     * @param keyCode The key code of the event.
+     * @param metaState The meta key modifier state.
+     * @return True if invoked the shortcut, otherwise false.
+     */
+    private boolean handleShortcutService(int keyCode, int metaState) {
+        long shortcutCode = keyCode;
+        if ((metaState & KeyEvent.META_CTRL_ON) != 0) {
+            shortcutCode |= ((long) KeyEvent.META_CTRL_ON) << Integer.SIZE;
+        }
+
+        if ((metaState & KeyEvent.META_ALT_ON) != 0) {
+            shortcutCode |= ((long) KeyEvent.META_ALT_ON) << Integer.SIZE;
+        }
+
+        if ((metaState & KeyEvent.META_SHIFT_ON) != 0) {
+            shortcutCode |= ((long) KeyEvent.META_SHIFT_ON) << Integer.SIZE;
+        }
+
+        if ((metaState & KeyEvent.META_META_ON) != 0) {
+            shortcutCode |= ((long) KeyEvent.META_META_ON) << Integer.SIZE;
+        }
+
+        IShortcutService shortcutService = mShortcutKeyServices.get(shortcutCode);
+        if (shortcutService != null) {
+            try {
+                shortcutService.notifyShortcutKeyPressed(shortcutCode);
+            } catch (RemoteException e) {
+                mShortcutKeyServices.delete(shortcutCode);
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Handle the shortcut to {@link Intent}
+     *
+     * @param kcm the {@link KeyCharacterMap} associated with the keyboard device.
+     * @param keyCode The key code of the event.
+     * @param metaState The meta key modifier state.
+     * @return True if invoked the shortcut, otherwise false.
+     */
+    private boolean handleIntentShortcut(KeyCharacterMap kcm, int keyCode, int metaState) {
+        // Shortcuts are invoked through Search+key, so intercept those here
+        // Any printing key that is chorded with Search should be consumed
+        // even if no shortcut was invoked.  This prevents text from being
+        // inadvertently inserted when using a keyboard that has built-in macro
+        // shortcut keys (that emit Search+x) and some of them are not registered.
+        if (mSearchKeyShortcutPending) {
+            if (kcm.isPrintingKey(keyCode)) {
+                mConsumeSearchKeyUp = true;
+                mSearchKeyShortcutPending = false;
+            } else {
+                return false;
+            }
+        } else if ((metaState & KeyEvent.META_META_MASK) != 0) {
+            // Invoke shortcuts using Meta.
+            metaState &= ~KeyEvent.META_META_MASK;
+        } else {
+            // Handle application launch keys.
+            String category = sApplicationLaunchKeyCategories.get(keyCode);
+            if (category != null) {
+                Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                try {
+                    mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+                } catch (ActivityNotFoundException ex) {
+                    Slog.w(TAG, "Dropping application launch key because "
+                            + "the activity to which it is registered was not found: "
+                            + "keyCode=" + KeyEvent.keyCodeToString(keyCode) + ","
+                            + " category=" + category, ex);
+                }
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        final Intent shortcutIntent = getIntent(kcm, keyCode, metaState);
+        if (shortcutIntent != null) {
+            shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            try {
+                mContext.startActivityAsUser(shortcutIntent, UserHandle.CURRENT);
+            } catch (ActivityNotFoundException ex) {
+                Slog.w(TAG, "Dropping shortcut key combination because "
+                        + "the activity to which it is registered was not found: "
+                        + "META+ or SEARCH" + KeyEvent.keyCodeToString(keyCode), ex);
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Handle the shortcut from {@link KeyEvent}
+     *
+     * @param event Description of the key event.
+     * @return True if invoked the shortcut, otherwise false.
+     */
+    boolean interceptKey(KeyEvent event) {
+        if (event.getRepeatCount() != 0) {
+            return false;
+        }
+
+        final int metaState = event.getModifiers();
+        final int keyCode = event.getKeyCode();
+        if (keyCode == KeyEvent.KEYCODE_SEARCH) {
+            if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                mSearchKeyShortcutPending = true;
+                mConsumeSearchKeyUp = false;
+            } else {
+                mSearchKeyShortcutPending = false;
+                if (mConsumeSearchKeyUp) {
+                    mConsumeSearchKeyUp = false;
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        if (event.getAction() != KeyEvent.ACTION_DOWN) {
+            return false;
+        }
+
+        final KeyCharacterMap kcm = event.getKeyCharacterMap();
+        if (handleIntentShortcut(kcm, keyCode, metaState)) {
+            return true;
+        }
+
+        if (handleShortcutService(keyCode, metaState)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    private static final class ShortcutInfo {
+        public final String title;
+        public final Intent intent;
+
+        ShortcutInfo(String title, Intent intent) {
+            this.title = title;
+            this.intent = intent;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 4ccd57d..bce218f 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -163,7 +163,6 @@
 import android.speech.RecognizerIntent;
 import android.telecom.TelecomManager;
 import android.util.Log;
-import android.util.LongSparseArray;
 import android.util.MutableBoolean;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
@@ -318,29 +317,6 @@
      */
     private boolean mKeyguardDrawnOnce;
 
-    /* Table of Application Launch keys.  Maps from key codes to intent categories.
-     *
-     * These are special keys that are used to launch particular kinds of applications,
-     * such as a web browser.  HID defines nearly a hundred of them in the Consumer (0x0C)
-     * usage page.  We don't support quite that many yet...
-     */
-    static SparseArray<String> sApplicationLaunchKeyCategories;
-    static {
-        sApplicationLaunchKeyCategories = new SparseArray<String>();
-        sApplicationLaunchKeyCategories.append(
-                KeyEvent.KEYCODE_EXPLORER, Intent.CATEGORY_APP_BROWSER);
-        sApplicationLaunchKeyCategories.append(
-                KeyEvent.KEYCODE_ENVELOPE, Intent.CATEGORY_APP_EMAIL);
-        sApplicationLaunchKeyCategories.append(
-                KeyEvent.KEYCODE_CONTACTS, Intent.CATEGORY_APP_CONTACTS);
-        sApplicationLaunchKeyCategories.append(
-                KeyEvent.KEYCODE_CALENDAR, Intent.CATEGORY_APP_CALENDAR);
-        sApplicationLaunchKeyCategories.append(
-                KeyEvent.KEYCODE_MUSIC, Intent.CATEGORY_APP_MUSIC);
-        sApplicationLaunchKeyCategories.append(
-                KeyEvent.KEYCODE_CALCULATOR, Intent.CATEGORY_APP_CALCULATOR);
-    }
-
     /** Amount of time (in milliseconds) to wait for windows drawn before powering on. */
     static final int WAITING_FOR_DRAWN_TIMEOUT = 1000;
 
@@ -419,8 +395,6 @@
     boolean mSafeMode;
     private WindowState mKeyguardCandidate = null;
 
-    private LongSparseArray<IShortcutService> mShortcutKeyServices = new LongSparseArray<>();
-
     // Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key.
     // This is for car dock and this is updated from resource.
     private boolean mEnableCarDockHomeCapture = true;
@@ -516,12 +490,8 @@
     Intent mCarDockIntent;
     Intent mDeskDockIntent;
     Intent mVrHeadsetHomeIntent;
-    boolean mSearchKeyShortcutPending;
-    boolean mConsumeSearchKeyUp;
     boolean mPendingMetaAction;
     boolean mPendingCapsLockToggle;
-    int mMetaState;
-    int mInitialMetaState;
 
     // support for activating the lock screen while the screen is on
     private HashSet<Integer> mAllowLockscreenWhenOnDisplays = new HashSet<>();
@@ -580,7 +550,7 @@
     private static final int BRIGHTNESS_STEPS = 10;
 
     SettingsObserver mSettingsObserver;
-    ShortcutManager mShortcutManager;
+    ModifierShortcutManager mModifierShortcutManager;
     PowerManager.WakeLock mBroadcastWakeLock;
     PowerManager.WakeLock mPowerKeyWakeLock;
     boolean mHavePendingMediaKeyRepeatWithWakeLock;
@@ -1774,7 +1744,7 @@
         mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler);
         mSettingsObserver = new SettingsObserver(mHandler);
         mSettingsObserver.observe();
-        mShortcutManager = new ShortcutManager(context);
+        mModifierShortcutManager = new ModifierShortcutManager(context);
         mUiMode = context.getResources().getInteger(
                 com.android.internal.R.integer.config_defaultUiModeType);
         mHomeIntent =  new Intent(Intent.ACTION_MAIN, null);
@@ -2547,6 +2517,7 @@
         final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
         final boolean canceled = event.isCanceled();
         final int displayId = event.getDisplayId();
+        final long key_consumed = -1;
 
         if (DEBUG_INPUT) {
             Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount="
@@ -2554,7 +2525,7 @@
         }
 
         if (mKeyCombinationManager.isKeyConsumed(event)) {
-            return -1;
+            return key_consumed;
         }
 
         if ((flags & KeyEvent.FLAG_FALLBACK) == 0) {
@@ -2575,344 +2546,255 @@
             mPendingCapsLockToggle = false;
         }
 
-        // First we always handle the home key here, so applications
-        // can never break it, although if keyguard is on, we do let
-        // it handle it, because that gives us the correct 5 second
-        // timeout.
-        if (keyCode == KEYCODE_HOME) {
-            DisplayHomeButtonHandler handler = mDisplayHomeButtonHandlers.get(displayId);
-            if (handler == null) {
-                handler = new DisplayHomeButtonHandler(displayId);
-                mDisplayHomeButtonHandlers.put(displayId, handler);
+        if (isUserSetupComplete() && !keyguardOn) {
+            if (mModifierShortcutManager.interceptKey(event)) {
+                dismissKeyboardShortcutsMenu();
+                mPendingMetaAction = false;
+                mPendingCapsLockToggle = false;
+                return key_consumed;
             }
-            return handler.handleHomeButton(focusedToken, event);
-        } else if (keyCode == KeyEvent.KEYCODE_MENU) {
-            // Hijack modified menu keys for debugging features
-            final int chordBug = KeyEvent.META_SHIFT_ON;
+        }
 
-            if (down && repeatCount == 0) {
-                if (mEnableShiftMenuBugReports && (metaState & chordBug) == chordBug) {
-                    Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
-                    mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT,
-                            null, null, null, 0, null, null);
-                    return -1;
+        switch(keyCode) {
+            case KeyEvent.KEYCODE_HOME:
+                // First we always handle the home key here, so applications
+                // can never break it, although if keyguard is on, we do let
+                // it handle it, because that gives us the correct 5 second
+                // timeout.
+                DisplayHomeButtonHandler handler = mDisplayHomeButtonHandlers.get(displayId);
+                if (handler == null) {
+                    handler = new DisplayHomeButtonHandler(displayId);
+                    mDisplayHomeButtonHandlers.put(displayId, handler);
                 }
-            }
-        } else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
-            if (down) {
-                if (repeatCount == 0) {
-                    mSearchKeyShortcutPending = true;
-                    mConsumeSearchKeyUp = false;
-                }
-            } else {
-                mSearchKeyShortcutPending = false;
-                if (mConsumeSearchKeyUp) {
-                    mConsumeSearchKeyUp = false;
-                    return -1;
-                }
-            }
-            return 0;
-        } else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) {
-            if (!keyguardOn) {
+                return handler.handleHomeButton(focusedToken, event);
+            case KeyEvent.KEYCODE_MENU:
+                // Hijack modified menu keys for debugging features
+                final int chordBug = KeyEvent.META_SHIFT_ON;
+
                 if (down && repeatCount == 0) {
-                    preloadRecentApps();
-                } else if (!down) {
-                    toggleRecentApps();
-                }
-            }
-            return -1;
-        } else if (keyCode == KeyEvent.KEYCODE_N && event.isMetaPressed()) {
-            if (down) {
-                IStatusBarService service = getStatusBarService();
-                if (service != null) {
-                    try {
-                        service.expandNotificationsPanel();
-                    } catch (RemoteException e) {
-                        // do nothing.
+                    if (mEnableShiftMenuBugReports && (metaState & chordBug) == chordBug) {
+                        Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
+                        mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT,
+                                null, null, null, 0, null, null);
+                        return key_consumed;
                     }
                 }
-            }
-        } else if (keyCode == KeyEvent.KEYCODE_S && event.isMetaPressed()
-                && event.isCtrlPressed()) {
-            if (down && repeatCount == 0) {
-                int type = event.isShiftPressed() ? TAKE_SCREENSHOT_SELECTED_REGION
-                        : TAKE_SCREENSHOT_FULLSCREEN;
-                mScreenshotRunnable.setScreenshotType(type);
-                mScreenshotRunnable.setScreenshotSource(SCREENSHOT_KEY_OTHER);
-                mHandler.post(mScreenshotRunnable);
-                return -1;
-            }
-        } else if (keyCode == KeyEvent.KEYCODE_SLASH && event.isMetaPressed()) {
-            if (down && repeatCount == 0 && !isKeyguardLocked()) {
-                toggleKeyboardShortcutsMenu(event.getDeviceId());
-            }
-        } else if (keyCode == KeyEvent.KEYCODE_ASSIST) {
-            Slog.wtf(TAG, "KEYCODE_ASSIST should be handled in interceptKeyBeforeQueueing");
-            return -1;
-        } else if (keyCode == KeyEvent.KEYCODE_VOICE_ASSIST) {
-            Slog.wtf(TAG, "KEYCODE_VOICE_ASSIST should be handled in interceptKeyBeforeQueueing");
-            return -1;
-        } else if (keyCode == KeyEvent.KEYCODE_SYSRQ) {
-            if (down && repeatCount == 0) {
-                mScreenshotRunnable.setScreenshotType(TAKE_SCREENSHOT_FULLSCREEN);
-                mScreenshotRunnable.setScreenshotSource(SCREENSHOT_KEY_OTHER);
-                mHandler.post(mScreenshotRunnable);
-            }
-            return -1;
-        } else if (keyCode == KeyEvent.KEYCODE_BRIGHTNESS_UP
-                || keyCode == KeyEvent.KEYCODE_BRIGHTNESS_DOWN) {
-            if (down) {
-                int direction = keyCode == KeyEvent.KEYCODE_BRIGHTNESS_UP ? 1 : -1;
+                break;
+            case KeyEvent.KEYCODE_APP_SWITCH:
+                if (!keyguardOn) {
+                    if (down && repeatCount == 0) {
+                        preloadRecentApps();
+                    } else if (!down) {
+                        toggleRecentApps();
+                    }
+                }
+                return key_consumed;
+            case KeyEvent.KEYCODE_N:
+                if (down && event.isMetaPressed()) {
+                    IStatusBarService service = getStatusBarService();
+                    if (service != null) {
+                        try {
+                            service.expandNotificationsPanel();
+                        } catch (RemoteException e) {
+                            // do nothing.
+                        }
+                        return key_consumed;
+                    }
+                }
+                break;
+            case KeyEvent.KEYCODE_S:
+                if (down && event.isMetaPressed() && event.isCtrlPressed() && repeatCount == 0) {
+                    int type = event.isShiftPressed() ? TAKE_SCREENSHOT_SELECTED_REGION
+                            : TAKE_SCREENSHOT_FULLSCREEN;
+                    mScreenshotRunnable.setScreenshotType(type);
+                    mScreenshotRunnable.setScreenshotSource(SCREENSHOT_KEY_OTHER);
+                    mHandler.post(mScreenshotRunnable);
+                    return key_consumed;
+                }
+                break;
+            case KeyEvent.KEYCODE_SLASH:
+                if (down && repeatCount == 0 && event.isMetaPressed() && !keyguardOn) {
+                    toggleKeyboardShortcutsMenu(event.getDeviceId());
+                    return key_consumed;
+                }
+                break;
+            case KeyEvent.KEYCODE_ASSIST:
+                Slog.wtf(TAG, "KEYCODE_ASSIST should be handled in interceptKeyBeforeQueueing");
+                return key_consumed;
+            case KeyEvent.KEYCODE_VOICE_ASSIST:
+                Slog.wtf(TAG, "KEYCODE_VOICE_ASSIST should be handled in"
+                        + " interceptKeyBeforeQueueing");
+                return key_consumed;
+            case KeyEvent.KEYCODE_SYSRQ:
+                if (down && repeatCount == 0) {
+                    mScreenshotRunnable.setScreenshotType(TAKE_SCREENSHOT_FULLSCREEN);
+                    mScreenshotRunnable.setScreenshotSource(SCREENSHOT_KEY_OTHER);
+                    mHandler.post(mScreenshotRunnable);
+                }
+                return key_consumed;
+            case KeyEvent.KEYCODE_BRIGHTNESS_UP:
+            case KeyEvent.KEYCODE_BRIGHTNESS_DOWN:
+                if (down) {
+                    int direction = keyCode == KeyEvent.KEYCODE_BRIGHTNESS_UP ? 1 : -1;
 
-                // Disable autobrightness if it's on
-                int auto = Settings.System.getIntForUser(
-                        mContext.getContentResolver(),
-                        Settings.System.SCREEN_BRIGHTNESS_MODE,
-                        Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
-                        UserHandle.USER_CURRENT_OR_SELF);
-                if (auto != 0) {
-                    Settings.System.putIntForUser(mContext.getContentResolver(),
+                    // Disable autobrightness if it's on
+                    int auto = Settings.System.getIntForUser(
+                            mContext.getContentResolver(),
                             Settings.System.SCREEN_BRIGHTNESS_MODE,
                             Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
                             UserHandle.USER_CURRENT_OR_SELF);
+                    if (auto != 0) {
+                        Settings.System.putIntForUser(mContext.getContentResolver(),
+                                Settings.System.SCREEN_BRIGHTNESS_MODE,
+                                Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
+                                UserHandle.USER_CURRENT_OR_SELF);
+                    }
+                    float minFloat = mPowerManager.getBrightnessConstraint(
+                            PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM);
+                    float maxFloat = mPowerManager.getBrightnessConstraint(
+                            PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM);
+                    float stepFloat = (maxFloat - minFloat) / BRIGHTNESS_STEPS * direction;
+                    float brightnessFloat = Settings.System.getFloatForUser(
+                            mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_FLOAT,
+                            mContext.getDisplay().getBrightnessDefault(),
+                            UserHandle.USER_CURRENT_OR_SELF);
+                    brightnessFloat += stepFloat;
+                    // Make sure we don't go beyond the limits.
+                    brightnessFloat = Math.min(maxFloat, brightnessFloat);
+                    brightnessFloat = Math.max(minFloat, brightnessFloat);
+
+                    Settings.System.putFloatForUser(mContext.getContentResolver(),
+                            Settings.System.SCREEN_BRIGHTNESS_FLOAT, brightnessFloat,
+                            UserHandle.USER_CURRENT_OR_SELF);
+                    startActivityAsUser(new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG),
+                            UserHandle.CURRENT_OR_SELF);
                 }
-                float minFloat = mPowerManager.getBrightnessConstraint(
-                        PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM);
-                float maxFloat = mPowerManager.getBrightnessConstraint(
-                        PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM);
-                float stepFloat = (maxFloat - minFloat) / BRIGHTNESS_STEPS * direction;
-                float brightnessFloat = Settings.System.getFloatForUser(
-                        mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_FLOAT,
-                        mContext.getDisplay().getBrightnessDefault(),
-                        UserHandle.USER_CURRENT_OR_SELF);
-                brightnessFloat += stepFloat;
-                // Make sure we don't go beyond the limits.
-                brightnessFloat = Math.min(maxFloat, brightnessFloat);
-                brightnessFloat = Math.max(minFloat, brightnessFloat);
-
-                Settings.System.putFloatForUser(mContext.getContentResolver(),
-                        Settings.System.SCREEN_BRIGHTNESS_FLOAT, brightnessFloat,
-                        UserHandle.USER_CURRENT_OR_SELF);
-                startActivityAsUser(new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG),
-                        UserHandle.CURRENT_OR_SELF);
-            }
-            return -1;
-        } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP
-                || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
-                || keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) {
-            if (mUseTvRouting || mHandleVolumeKeysInWM) {
-                // On TVs or when the configuration is enabled, volume keys never
-                // go to the foreground app.
-                dispatchDirectAudioEvent(event);
-                return -1;
-            }
-
-            // If the device is in VR mode and keys are "internal" (e.g. on the side of the
-            // device), then drop the volume keys and don't forward it to the application/dispatch
-            // the audio event.
-            if (mDefaultDisplayPolicy.isPersistentVrModeEnabled()) {
-                final InputDevice d = event.getDevice();
-                if (d != null && !d.isExternal()) {
-                    return -1;
+                return key_consumed;
+            case KeyEvent.KEYCODE_VOLUME_UP:
+            case KeyEvent.KEYCODE_VOLUME_DOWN:
+            case KeyEvent.KEYCODE_VOLUME_MUTE:
+                if (mUseTvRouting || mHandleVolumeKeysInWM) {
+                    // On TVs or when the configuration is enabled, volume keys never
+                    // go to the foreground app.
+                    dispatchDirectAudioEvent(event);
+                    return key_consumed;
                 }
-            }
-        } else if (keyCode == KeyEvent.KEYCODE_TAB && event.isMetaPressed()) {
-            // Pass through keyboard navigation keys.
-            return 0;
-        } else if (keyCode == KeyEvent.KEYCODE_ALL_APPS) {
-            if (!down) {
-                mHandler.removeMessages(MSG_HANDLE_ALL_APPS);
-                Message msg = mHandler.obtainMessage(MSG_HANDLE_ALL_APPS);
-                msg.setAsynchronous(true);
-                msg.sendToTarget();
-            }
-            return -1;
-        } else if (keyCode == KeyEvent.KEYCODE_NOTIFICATION) {
-            if (!down) {
-                toggleNotificationPanel();
-            }
-            return -1;
-        }
 
-        // Toggle Caps Lock on META-ALT.
-        boolean actionTriggered = false;
-        if (KeyEvent.isModifierKey(keyCode)) {
-            if (!mPendingCapsLockToggle) {
-                // Start tracking meta state for combo.
-                mInitialMetaState = mMetaState;
-                mPendingCapsLockToggle = true;
-            } else if (event.getAction() == KeyEvent.ACTION_UP) {
-                int altOnMask = mMetaState & KeyEvent.META_ALT_MASK;
-                int metaOnMask = mMetaState & KeyEvent.META_META_MASK;
-
-                // Check for Caps Lock toggle
-                if ((metaOnMask != 0) && (altOnMask != 0)) {
-                    // Check if nothing else is pressed
-                    if (mInitialMetaState == (mMetaState ^ (altOnMask | metaOnMask))) {
-                        // Handle Caps Lock Toggle
-                        mInputManagerInternal.toggleCapsLock(event.getDeviceId());
-                        actionTriggered = true;
+                // If the device is in VR mode and keys are "internal" (e.g. on the side of the
+                // device), then drop the volume keys and don't forward it to the
+                // application/dispatch the audio event.
+                if (mDefaultDisplayPolicy.isPersistentVrModeEnabled()) {
+                    final InputDevice d = event.getDevice();
+                    if (d != null && !d.isExternal()) {
+                        return key_consumed;
                     }
                 }
-
-                // Always stop tracking when key goes up.
-                mPendingCapsLockToggle = false;
-            }
-        }
-        // Store current meta state to be able to evaluate it later.
-        mMetaState = metaState;
-
-        if (actionTriggered) {
-            return -1;
-        }
-
-        if (KeyEvent.isMetaKey(keyCode)) {
-            if (down) {
-                mPendingMetaAction = true;
-            } else if (mPendingMetaAction) {
-                launchAssistAction(Intent.EXTRA_ASSIST_INPUT_HINT_KEYBOARD, event.getDeviceId(),
-                        event.getEventTime());
-            }
-            return -1;
-        }
-
-        // Shortcuts are invoked through Search+key, so intercept those here
-        // Any printing key that is chorded with Search should be consumed
-        // even if no shortcut was invoked.  This prevents text from being
-        // inadvertently inserted when using a keyboard that has built-in macro
-        // shortcut keys (that emit Search+x) and some of them are not registered.
-        if (mSearchKeyShortcutPending) {
-            final KeyCharacterMap kcm = event.getKeyCharacterMap();
-            if (kcm.isPrintingKey(keyCode)) {
-                mConsumeSearchKeyUp = true;
-                mSearchKeyShortcutPending = false;
-                if (down && repeatCount == 0 && !keyguardOn) {
-                    Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode, metaState);
-                    if (shortcutIntent != null) {
-                        shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                        try {
-                            startActivityAsUser(shortcutIntent, UserHandle.CURRENT);
-                            dismissKeyboardShortcutsMenu();
-                        } catch (ActivityNotFoundException ex) {
-                            Slog.w(TAG, "Dropping shortcut key combination because "
-                                    + "the activity to which it is registered was not found: "
-                                    + "SEARCH+" + KeyEvent.keyCodeToString(keyCode), ex);
+                break;
+            case KeyEvent.KEYCODE_TAB:
+                if (event.isMetaPressed()) {
+                    // Pass through keyboard navigation keys.
+                    return 0;
+                }
+                // Display task switcher for ALT-TAB.
+                if (down && repeatCount == 0) {
+                    if (mRecentAppsHeldModifiers == 0 && !keyguardOn && isUserSetupComplete()) {
+                        final int shiftlessModifiers =
+                                event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
+                        if (KeyEvent.metaStateHasModifiers(
+                                shiftlessModifiers, KeyEvent.META_ALT_ON)) {
+                            mRecentAppsHeldModifiers = shiftlessModifiers;
+                            showRecentApps(true);
+                            return key_consumed;
                         }
+                    }
+                }
+                break;
+            case KeyEvent.KEYCODE_ALL_APPS:
+                if (!down) {
+                    mHandler.removeMessages(MSG_HANDLE_ALL_APPS);
+                    Message msg = mHandler.obtainMessage(MSG_HANDLE_ALL_APPS);
+                    msg.setAsynchronous(true);
+                    msg.sendToTarget();
+                }
+                return key_consumed;
+            case KeyEvent.KEYCODE_NOTIFICATION:
+                if (!down) {
+                    toggleNotificationPanel();
+                }
+                return key_consumed;
+
+            case KeyEvent.KEYCODE_SPACE:
+                // Handle keyboard layout switching.
+                if ((metaState & (KeyEvent.META_CTRL_MASK | KeyEvent.META_META_MASK)) == 0) {
+                    return 0;
+                }
+                // Share the same behavior with KEYCODE_LANGUAGE_SWITCH.
+            case KeyEvent.KEYCODE_LANGUAGE_SWITCH:
+                if (down && repeatCount == 0) {
+                    int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
+                    mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction);
+                    return key_consumed;
+                }
+                break;
+            case KeyEvent.KEYCODE_META_LEFT:
+            case KeyEvent.KEYCODE_META_RIGHT:
+                if (down) {
+                    if (event.isAltPressed()) {
+                        mPendingCapsLockToggle = true;
+                        mPendingMetaAction = false;
                     } else {
-                        Slog.i(TAG, "Dropping unregistered shortcut key combination: "
-                                + "SEARCH+" + KeyEvent.keyCodeToString(keyCode));
+                        mPendingCapsLockToggle = false;
+                        mPendingMetaAction = true;
+                    }
+                } else {
+                    // Toggle Caps Lock on META-ALT.
+                    if (mPendingCapsLockToggle) {
+                        mInputManagerInternal.toggleCapsLock(event.getDeviceId());
+                        mPendingCapsLockToggle = false;
+                    } else if (mPendingMetaAction) {
+                        launchAssistAction(Intent.EXTRA_ASSIST_INPUT_HINT_KEYBOARD,
+                                event.getDeviceId(),
+                                event.getEventTime());
+                        mPendingMetaAction = false;
                     }
                 }
-                return -1;
-            }
-        }
-
-        // Invoke shortcuts using Meta.
-        if (down && repeatCount == 0 && !keyguardOn
-                && (metaState & KeyEvent.META_META_ON) != 0) {
-            final KeyCharacterMap kcm = event.getKeyCharacterMap();
-            if (kcm.isPrintingKey(keyCode)) {
-                Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode,
-                        metaState & ~(KeyEvent.META_META_ON
-                                | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON));
-                if (shortcutIntent != null) {
-                    shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    try {
-                        startActivityAsUser(shortcutIntent, UserHandle.CURRENT);
-                        dismissKeyboardShortcutsMenu();
-                    } catch (ActivityNotFoundException ex) {
-                        Slog.w(TAG, "Dropping shortcut key combination because "
-                                + "the activity to which it is registered was not found: "
-                                + "META+" + KeyEvent.keyCodeToString(keyCode), ex);
+                return key_consumed;
+            case KeyEvent.KEYCODE_ALT_LEFT:
+            case KeyEvent.KEYCODE_ALT_RIGHT:
+                if (down) {
+                    if (event.isMetaPressed()) {
+                        mPendingCapsLockToggle = true;
+                        mPendingMetaAction = false;
+                    } else {
+                        mPendingCapsLockToggle = false;
                     }
-                    return -1;
-                }
-            }
-        }
+                } else {
+                    // hide recent if triggered by ALT-TAB.
+                    if (mRecentAppsHeldModifiers != 0
+                            && (metaState & mRecentAppsHeldModifiers) == 0) {
+                        mRecentAppsHeldModifiers = 0;
+                        hideRecentApps(true, false);
+                        return key_consumed;
+                    }
 
-        // Handle application launch keys.
-        if (down && repeatCount == 0 && !keyguardOn) {
-            String category = sApplicationLaunchKeyCategories.get(keyCode);
-            if (category != null) {
-                Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category);
-                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                try {
-                    startActivityAsUser(intent, UserHandle.CURRENT);
-                    dismissKeyboardShortcutsMenu();
-                } catch (ActivityNotFoundException ex) {
-                    Slog.w(TAG, "Dropping application launch key because "
-                            + "the activity to which it is registered was not found: "
-                            + "keyCode=" + keyCode + ", category=" + category, ex);
+                    // Toggle Caps Lock on META-ALT.
+                    if (mPendingCapsLockToggle) {
+                        mInputManagerInternal.toggleCapsLock(event.getDeviceId());
+                        mPendingCapsLockToggle = false;
+                        return key_consumed;
+                    }
                 }
-                return -1;
-            }
-        }
-
-        // Display task switcher for ALT-TAB.
-        if (down && repeatCount == 0 && keyCode == KeyEvent.KEYCODE_TAB) {
-            if (mRecentAppsHeldModifiers == 0 && !keyguardOn && isUserSetupComplete()) {
-                final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
-                if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON)) {
-                    mRecentAppsHeldModifiers = shiftlessModifiers;
-                    showRecentApps(true);
-                    return -1;
-                }
-            }
-        } else if (!down && mRecentAppsHeldModifiers != 0
-                && (metaState & mRecentAppsHeldModifiers) == 0) {
-            mRecentAppsHeldModifiers = 0;
-            hideRecentApps(true, false);
-        }
-
-        // Handle keyboard language switching.
-        final boolean isCtrlOrMetaSpace = keyCode == KeyEvent.KEYCODE_SPACE
-                && (metaState & (KeyEvent.META_CTRL_MASK | KeyEvent.META_META_MASK)) != 0;
-        if (down && repeatCount == 0
-                && (keyCode == KeyEvent.KEYCODE_LANGUAGE_SWITCH || isCtrlOrMetaSpace)) {
-            int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
-            mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction);
-            return -1;
+                break;
         }
 
         if (isValidGlobalKey(keyCode)
                 && mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) {
-            return -1;
-        }
-
-        if (down) {
-            long shortcutCode = keyCode;
-            if (event.isCtrlPressed()) {
-                shortcutCode |= ((long) KeyEvent.META_CTRL_ON) << Integer.SIZE;
-            }
-
-            if (event.isAltPressed()) {
-                shortcutCode |= ((long) KeyEvent.META_ALT_ON) << Integer.SIZE;
-            }
-
-            if (event.isShiftPressed()) {
-                shortcutCode |= ((long) KeyEvent.META_SHIFT_ON) << Integer.SIZE;
-            }
-
-            if (event.isMetaPressed()) {
-                shortcutCode |= ((long) KeyEvent.META_META_ON) << Integer.SIZE;
-            }
-
-            IShortcutService shortcutService = mShortcutKeyServices.get(shortcutCode);
-            if (shortcutService != null) {
-                try {
-                    if (isUserSetupComplete()) {
-                        shortcutService.notifyShortcutKeyPressed(shortcutCode);
-                    }
-                } catch (RemoteException e) {
-                    mShortcutKeyServices.delete(shortcutCode);
-                }
-                return -1;
-            }
+            return key_consumed;
         }
 
         // Reserve all the META modifier combos for system behavior
         if ((metaState & KeyEvent.META_META_ON) != 0) {
-            return -1;
+            return key_consumed;
         }
 
         // Let the application handle the key.
@@ -3095,12 +2977,7 @@
     public void registerShortcutKey(long shortcutCode, IShortcutService shortcutService)
             throws RemoteException {
         synchronized (mLock) {
-            IShortcutService service = mShortcutKeyServices.get(shortcutCode);
-            if (service != null && service.asBinder().pingBinder()) {
-                throw new RemoteException("Key already exists.");
-            }
-
-            mShortcutKeyServices.put(shortcutCode, shortcutService);
+            mModifierShortcutManager.registerShortcutKey(shortcutCode, shortcutService);
         }
     }
 
diff --git a/services/core/java/com/android/server/policy/ShortcutManager.java b/services/core/java/com/android/server/policy/ShortcutManager.java
deleted file mode 100644
index ab404db..0000000
--- a/services/core/java/com/android/server/policy/ShortcutManager.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2007 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.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.res.XmlResourceParser;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
-
-import com.android.internal.util.XmlUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-
-/**
- * Manages quick launch shortcuts by:
- * <li> Keeping the local copy in sync with the database (this is an observer)
- * <li> Returning a shortcut-matching intent to clients
- */
-class ShortcutManager {
-    private static final String TAG = "ShortcutManager";
-
-    private static final String TAG_BOOKMARKS = "bookmarks";
-    private static final String TAG_BOOKMARK = "bookmark";
-
-    private static final String ATTRIBUTE_PACKAGE = "package";
-    private static final String ATTRIBUTE_CLASS = "class";
-    private static final String ATTRIBUTE_SHORTCUT = "shortcut";
-    private static final String ATTRIBUTE_CATEGORY = "category";
-    private static final String ATTRIBUTE_SHIFT = "shift";
-
-    private final SparseArray<ShortcutInfo> mShortcuts = new SparseArray<>();
-    private final SparseArray<ShortcutInfo> mShiftShortcuts = new SparseArray<>();
-
-    private final Context mContext;
-    
-    public ShortcutManager(Context context) {
-        mContext = context;
-        loadShortcuts();
-    }
-
-    /**
-     * Gets the shortcut intent for a given keycode+modifier. Make sure you
-     * strip whatever modifier is used for invoking shortcuts (for example,
-     * if 'Sym+A' should invoke a shortcut on 'A', you should strip the
-     * 'Sym' bit from the modifiers before calling this method.
-     * <p>
-     * This will first try an exact match (with modifiers), and then try a
-     * match without modifiers (primary character on a key).
-     * 
-     * @param kcm The key character map of the device on which the key was pressed.
-     * @param keyCode The key code.
-     * @param metaState The meta state, omitting any modifiers that were used
-     * to invoke the shortcut.
-     * @return The intent that matches the shortcut, or null if not found.
-     */
-    public Intent getIntent(KeyCharacterMap kcm, int keyCode, int metaState) {
-        ShortcutInfo shortcut = null;
-
-        // If the Shift key is pressed, then search for the shift shortcuts.
-        boolean isShiftOn = (metaState & KeyEvent.META_SHIFT_ON) == KeyEvent.META_SHIFT_ON;
-        SparseArray<ShortcutInfo> shortcutMap = isShiftOn ? mShiftShortcuts : mShortcuts;
-
-        // First try the exact keycode (with modifiers).
-        int shortcutChar = kcm.get(keyCode, metaState);
-        if (shortcutChar != 0) {
-            shortcut = shortcutMap.get(shortcutChar);
-        }
-
-        // Next try the primary character on that key.
-        if (shortcut == null) {
-            shortcutChar = Character.toLowerCase(kcm.getDisplayLabel(keyCode));
-            if (shortcutChar != 0) {
-                shortcut = shortcutMap.get(shortcutChar);
-            }
-        }
-
-        return (shortcut != null) ? shortcut.intent : null;
-    }
-
-    private void loadShortcuts() {
-        PackageManager packageManager = mContext.getPackageManager();
-        try {
-            XmlResourceParser parser = mContext.getResources().getXml(
-                    com.android.internal.R.xml.bookmarks);
-            XmlUtils.beginDocument(parser, TAG_BOOKMARKS);
-
-            while (true) {
-                XmlUtils.nextElement(parser);
-
-                if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
-                    break;
-                }
-
-                if (!TAG_BOOKMARK.equals(parser.getName())) {
-                    break;
-                }
-
-                String packageName = parser.getAttributeValue(null, ATTRIBUTE_PACKAGE);
-                String className = parser.getAttributeValue(null, ATTRIBUTE_CLASS);
-                String shortcutName = parser.getAttributeValue(null, ATTRIBUTE_SHORTCUT);
-                String categoryName = parser.getAttributeValue(null, ATTRIBUTE_CATEGORY);
-                String shiftName = parser.getAttributeValue(null, ATTRIBUTE_SHIFT);
-
-                if (TextUtils.isEmpty(shortcutName)) {
-                    Log.w(TAG, "Unable to get shortcut for: " + packageName + "/" + className);
-                    continue;
-                }
-
-                final int shortcutChar = shortcutName.charAt(0);
-                final boolean isShiftShortcut = (shiftName != null && shiftName.equals("true"));
-
-                final Intent intent;
-                final String title;
-                if (packageName != null && className != null) {
-                    ActivityInfo info = null;
-                    ComponentName componentName = new ComponentName(packageName, className);
-                    try {
-                        info = packageManager.getActivityInfo(componentName,
-                                PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
-                                        | PackageManager.MATCH_UNINSTALLED_PACKAGES);
-                    } catch (PackageManager.NameNotFoundException e) {
-                        String[] packages = packageManager.canonicalToCurrentPackageNames(
-                                new String[] { packageName });
-                        componentName = new ComponentName(packages[0], className);
-                        try {
-                            info = packageManager.getActivityInfo(componentName,
-                                    PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
-                                            | PackageManager.MATCH_UNINSTALLED_PACKAGES);
-                        } catch (PackageManager.NameNotFoundException e1) {
-                            Log.w(TAG, "Unable to add bookmark: " + packageName
-                                    + "/" + className, e);
-                            continue;
-                        }
-                    }
-
-                    intent = new Intent(Intent.ACTION_MAIN);
-                    intent.addCategory(Intent.CATEGORY_LAUNCHER);
-                    intent.setComponent(componentName);
-                    title = info.loadLabel(packageManager).toString();
-                } else if (categoryName != null) {
-                    intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, categoryName);
-                    title = "";
-                } else {
-                    Log.w(TAG, "Unable to add bookmark for shortcut " + shortcutName
-                            + ": missing package/class or category attributes");
-                    continue;
-                }
-
-                ShortcutInfo shortcut = new ShortcutInfo(title, intent);
-                if (isShiftShortcut) {
-                    mShiftShortcuts.put(shortcutChar, shortcut);
-                } else {
-                    mShortcuts.put(shortcutChar, shortcut);
-                }
-            }
-        } catch (XmlPullParserException e) {
-            Log.w(TAG, "Got exception parsing bookmarks.", e);
-        } catch (IOException e) {
-            Log.w(TAG, "Got exception parsing bookmarks.", e);
-        }
-    }
-
-    private static final class ShortcutInfo {
-        public final String title;
-        public final Intent intent;
-
-        public ShortcutInfo(String title, Intent intent) {
-            this.title = title;
-            this.intent = intent;
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 8c46445..bc11709 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -1645,7 +1645,7 @@
     }
 
     // Called from native code.
-    private void userActivityFromNative(long eventTime, int event, int flags) {
+    private void userActivityFromNative(long eventTime, int event, int displayId, int flags) {
         userActivityInternal(eventTime, event, flags, Process.SYSTEM_UID);
     }
 
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsLogger.java b/services/core/java/com/android/server/powerstats/PowerStatsLogger.java
index c4f29ea..ef0079e 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsLogger.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsLogger.java
@@ -16,6 +16,8 @@
 
 package com.android.server.powerstats;
 
+import static java.lang.System.currentTimeMillis;
+
 import android.content.Context;
 import android.hardware.power.stats.Channel;
 import android.hardware.power.stats.EnergyConsumer;
@@ -26,11 +28,14 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.SystemClock;
 import android.util.AtomicFile;
 import android.util.Slog;
 import android.util.proto.ProtoInputStream;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import com.android.server.powerstats.PowerStatsHALWrapper.IPowerStatsHALWrapper;
 import com.android.server.powerstats.ProtoStreamUtils.ChannelUtils;
 import com.android.server.powerstats.ProtoStreamUtils.EnergyConsumerResultUtils;
@@ -61,6 +66,8 @@
     protected static final int MSG_LOG_TO_DATA_STORAGE_LOW_FREQUENCY = 1;
     protected static final int MSG_LOG_TO_DATA_STORAGE_HIGH_FREQUENCY = 2;
 
+    // TODO(b/181240441): Add a listener to update the Wall clock baseline when changed
+    private final long mStartWallTime;
     private final PowerStatsDataStorage mPowerStatsMeterStorage;
     private final PowerStatsDataStorage mPowerStatsModelStorage;
     private final PowerStatsDataStorage mPowerStatsResidencyStorage;
@@ -79,6 +86,8 @@
                 // Log power meter data.
                 EnergyMeasurement[] energyMeasurements =
                     mPowerStatsHALWrapper.readEnergyMeter(new int[0]);
+                EnergyMeasurementUtils.adjustTimeSinceBootToEpoch(energyMeasurements,
+                        mStartWallTime);
                 mPowerStatsMeterStorage.write(
                         EnergyMeasurementUtils.getProtoBytes(energyMeasurements));
                 if (DEBUG) EnergyMeasurementUtils.print(energyMeasurements);
@@ -86,6 +95,8 @@
                 // Log power model data without attribution data.
                 EnergyConsumerResult[] ecrNoAttribution =
                     mPowerStatsHALWrapper.getEnergyConsumed(new int[0]);
+                EnergyConsumerResultUtils.adjustTimeSinceBootToEpoch(ecrNoAttribution,
+                        mStartWallTime);
                 mPowerStatsModelStorage.write(
                         EnergyConsumerResultUtils.getProtoBytes(ecrNoAttribution, false));
                 if (DEBUG) EnergyConsumerResultUtils.print(ecrNoAttribution);
@@ -97,6 +108,8 @@
                 // Log power model data with attribution data.
                 EnergyConsumerResult[] ecrAttribution =
                     mPowerStatsHALWrapper.getEnergyConsumed(new int[0]);
+                EnergyConsumerResultUtils.adjustTimeSinceBootToEpoch(ecrAttribution,
+                        mStartWallTime);
                 mPowerStatsModelStorage.write(
                         EnergyConsumerResultUtils.getProtoBytes(ecrAttribution, true));
                 if (DEBUG) EnergyConsumerResultUtils.print(ecrAttribution);
@@ -108,6 +121,8 @@
                 // Log state residency data.
                 StateResidencyResult[] stateResidencyResults =
                     mPowerStatsHALWrapper.getStateResidency(new int[0]);
+                StateResidencyResultUtils.adjustTimeSinceBootToEpoch(stateResidencyResults,
+                        mStartWallTime);
                 mPowerStatsResidencyStorage.write(
                         StateResidencyResultUtils.getProtoBytes(stateResidencyResults));
                 if (DEBUG) StateResidencyResultUtils.print(stateResidencyResults);
@@ -293,12 +308,19 @@
         return mDeleteResidencyDataOnBoot;
     }
 
+    @VisibleForTesting
+    public long getStartWallTime() {
+        return mStartWallTime;
+    }
+
     public PowerStatsLogger(Context context, File dataStoragePath,
             String meterFilename, String meterCacheFilename,
             String modelFilename, String modelCacheFilename,
             String residencyFilename, String residencyCacheFilename,
             IPowerStatsHALWrapper powerStatsHALWrapper) {
         super(Looper.getMainLooper());
+        mStartWallTime = currentTimeMillis() - SystemClock.elapsedRealtime();
+        if (DEBUG) Slog.d(TAG, "mStartWallTime: " + mStartWallTime);
         mPowerStatsHALWrapper = powerStatsHALWrapper;
         mDataStoragePath = dataStoragePath;
 
diff --git a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
index 11b22a5..746a098 100644
--- a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
+++ b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
@@ -109,6 +109,18 @@
     }
 
     static class StateResidencyResultUtils {
+        public static void adjustTimeSinceBootToEpoch(StateResidencyResult[] stateResidencyResult,
+                long startWallTime) {
+            for (int i = 0; i < stateResidencyResult.length; i++) {
+                final int stateLength = stateResidencyResult[i].stateResidencyData.length;
+                for (int j = 0; j < stateLength; j++) {
+                    final StateResidency stateResidencyData =
+                            stateResidencyResult[i].stateResidencyData[j];
+                    stateResidencyData.lastEntryTimestampMs += startWallTime;
+                }
+            }
+        }
+
         public static byte[] getProtoBytes(StateResidencyResult[] stateResidencyResult) {
             ProtoOutputStream pos = new ProtoOutputStream();
             packProtoMessage(stateResidencyResult, pos);
@@ -306,6 +318,13 @@
     }
 
     static class EnergyMeasurementUtils {
+        public static void adjustTimeSinceBootToEpoch(EnergyMeasurement[] energyMeasurement,
+                long startWallTime) {
+            for (int i = 0; i < energyMeasurement.length; i++) {
+                energyMeasurement[i].timestampMs += startWallTime;
+            }
+        }
+
         public static byte[] getProtoBytes(EnergyMeasurement[] energyMeasurement) {
             ProtoOutputStream pos = new ProtoOutputStream();
             packProtoMessage(energyMeasurement, pos);
@@ -518,6 +537,13 @@
     }
 
     static class EnergyConsumerResultUtils {
+        public static void adjustTimeSinceBootToEpoch(EnergyConsumerResult[] energyConsumerResult,
+                long startWallTime) {
+            for (int i = 0; i < energyConsumerResult.length; i++) {
+                energyConsumerResult[i].timestampMs += startWallTime;
+            }
+        }
+
         public static byte[] getProtoBytes(EnergyConsumerResult[] energyConsumerResult,
                 boolean includeAttribution) {
             ProtoOutputStream pos = new ProtoOutputStream();
diff --git a/services/core/java/com/android/server/role/OWNERS b/services/core/java/com/android/server/role/OWNERS
index 31e3549..dafdf0f 100644
--- a/services/core/java/com/android/server/role/OWNERS
+++ b/services/core/java/com/android/server/role/OWNERS
@@ -1,5 +1 @@
-svetoslavganov@google.com
-zhanghai@google.com
-evanseverson@google.com
-eugenesusla@google.com
-ntmyren@google.com
+include platform/frameworks/base:/core/java/android/permission/OWNERS
diff --git a/services/core/java/com/android/server/security/KeyChainSystemService.java b/services/core/java/com/android/server/security/KeyChainSystemService.java
index 3c06d0e..edd4a3d 100644
--- a/services/core/java/com/android/server/security/KeyChainSystemService.java
+++ b/services/core/java/com/android/server/security/KeyChainSystemService.java
@@ -16,6 +16,8 @@
 
 package com.android.server.security;
 
+import static android.os.PowerWhitelistManager.REASON_KEY_CHAIN;
+
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -102,7 +104,8 @@
         final DeviceIdleInternal idleController =
                 LocalServices.getService(DeviceIdleInternal.class);
         idleController.addPowerSaveTempWhitelistApp(Process.myUid(), packageName,
-                KEYCHAIN_IDLE_WHITELIST_DURATION_MS, user.getIdentifier(), false, "keychain");
+                KEYCHAIN_IDLE_WHITELIST_DURATION_MS, user.getIdentifier(), false,
+                REASON_KEY_CHAIN, "keychain");
 
         getContext().startServiceAsUser(intent, user);
     }
diff --git a/services/core/java/com/android/server/servicewatcher/OWNERS b/services/core/java/com/android/server/servicewatcher/OWNERS
new file mode 100644
index 0000000..ced619f
--- /dev/null
+++ b/services/core/java/com/android/server/servicewatcher/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 25692
+
+sooniln@google.com
+wyattriley@google.com
+
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/servicewatcher/ServiceWatcher.java
similarity index 81%
rename from services/core/java/com/android/server/ServiceWatcher.java
rename to services/core/java/com/android/server/servicewatcher/ServiceWatcher.java
index c2d8fa2..5d49663 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/servicewatcher/ServiceWatcher.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.servicewatcher;
 
 import static android.content.Context.BIND_AUTO_CREATE;
 import static android.content.Context.BIND_NOT_FOREGROUND;
@@ -45,14 +45,19 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.util.ArrayMap;
 import android.util.Log;
 
+import com.android.internal.annotations.Immutable;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.server.FgThread;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.function.Predicate;
 
@@ -87,26 +92,30 @@
     /** Function to run on binder interface when first bound. */
     public interface OnBindRunner {
         /** Called to run client code with the binder. */
-        void run(IBinder binder, ComponentName service) throws RemoteException;
+        void run(IBinder binder, BoundService service) throws RemoteException;
     }
 
     /**
      * Information on the service ServiceWatcher has selected as the best option for binding.
      */
-    private static final class ServiceInfo implements Comparable<ServiceInfo> {
+    @Immutable
+    public static final class BoundService implements Comparable<BoundService> {
 
-        public static final ServiceInfo NONE = new ServiceInfo(Integer.MIN_VALUE, null,
-                UserHandle.USER_NULL, false);
+        public static final BoundService NONE = new BoundService(Integer.MIN_VALUE, null,
+                false, null, -1);
 
         public final int version;
-        @Nullable public final ComponentName component;
-        @UserIdInt public final int userId;
+        @Nullable
+        public final ComponentName component;
         public final boolean serviceIsMultiuser;
+        public final int uid;
+        @Nullable
+        public final Bundle metadata;
 
-        ServiceInfo(ResolveInfo resolveInfo, int currentUserId) {
+        BoundService(ResolveInfo resolveInfo) {
             Preconditions.checkArgument(resolveInfo.serviceInfo.getComponentName() != null);
 
-            Bundle metadata = resolveInfo.serviceInfo.metaData;
+            metadata = resolveInfo.serviceInfo.metaData;
             if (metadata != null) {
                 version = metadata.getInt(EXTRA_SERVICE_VERSION, Integer.MIN_VALUE);
                 serviceIsMultiuser = metadata.getBoolean(EXTRA_SERVICE_IS_MULTIUSER, false);
@@ -116,16 +125,17 @@
             }
 
             component = resolveInfo.serviceInfo.getComponentName();
-            userId = serviceIsMultiuser ? UserHandle.USER_SYSTEM : currentUserId;
+            uid = resolveInfo.serviceInfo.applicationInfo.uid;
         }
 
-        private ServiceInfo(int version, @Nullable ComponentName component, int userId,
-                boolean serviceIsMultiuser) {
+        private BoundService(int version, @Nullable ComponentName component,
+                boolean serviceIsMultiuser, @Nullable Bundle metadata, int uid) {
             Preconditions.checkArgument(component != null || version == Integer.MIN_VALUE);
             this.version = version;
             this.component = component;
-            this.userId = userId;
             this.serviceIsMultiuser = serviceIsMultiuser;
+            this.metadata = metadata;
+            this.uid = uid;
         }
 
         public @Nullable String getPackageName() {
@@ -137,21 +147,21 @@
             if (this == o) {
                 return true;
             }
-            if (!(o instanceof ServiceInfo)) {
+            if (!(o instanceof BoundService)) {
                 return false;
             }
-            ServiceInfo that = (ServiceInfo) o;
-            return version == that.version && userId == that.userId
+            BoundService that = (BoundService) o;
+            return version == that.version && uid == that.uid
                     && Objects.equals(component, that.component);
         }
 
         @Override
         public int hashCode() {
-            return Objects.hash(version, component, userId);
+            return Objects.hash(version, component, uid);
         }
 
         @Override
-        public int compareTo(ServiceInfo that) {
+        public int compareTo(BoundService that) {
             // ServiceInfos with higher version numbers always win (having a version number >
             // MIN_VALUE implies having a non-null component). if version numbers are equal, a
             // non-null component wins over a null component. if the version numbers are equal and
@@ -164,10 +174,11 @@
                 } else if (component != null && that.component == null) {
                     ret = 1;
                 } else {
-                    if (userId != UserHandle.USER_SYSTEM && that.userId == UserHandle.USER_SYSTEM) {
+                    if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM
+                            && UserHandle.getUserId(that.uid) == UserHandle.USER_SYSTEM) {
                         ret = -1;
-                    } else if (userId == UserHandle.USER_SYSTEM
-                            && that.userId != UserHandle.USER_SYSTEM) {
+                    } else if (UserHandle.getUserId(uid) == UserHandle.USER_SYSTEM
+                            && UserHandle.getUserId(that.uid) != UserHandle.USER_SYSTEM) {
                         ret = 1;
                     }
                 }
@@ -180,7 +191,8 @@
             if (component == null) {
                 return "none";
             } else {
-                return component.toShortString() + "@" + version + "[u" + userId + "]";
+                return component.toShortString() + "@" + version + "[u"
+                        + UserHandle.getUserId(uid) + "]";
             }
         }
     }
@@ -227,17 +239,23 @@
         }
     };
 
-    @Nullable private final OnBindRunner mOnBind;
-    @Nullable private final Runnable mOnUnbind;
+    // read/write from handler thread only
+    private final Map<ComponentName, BoundService> mPendingBinds = new ArrayMap<>();
 
-    // write from caller thread only, read anywhere
-    private volatile boolean mRegistered;
+    @Nullable
+    private final OnBindRunner mOnBind;
+
+    @Nullable
+    private final Runnable mOnUnbind;
+
+    // read/write from handler thread only
+    private boolean mRegistered;
 
     // read/write from handler thread only
     private int mCurrentUserId;
 
     // write from handler thread only, read anywhere
-    private volatile ServiceInfo mTargetService;
+    private volatile BoundService mTargetService;
     private volatile IBinder mBinder;
 
     public ServiceWatcher(Context context, String action,
@@ -274,7 +292,7 @@
 
         mCurrentUserId = UserHandle.USER_NULL;
 
-        mTargetService = ServiceInfo.NONE;
+        mTargetService = BoundService.NONE;
         mBinder = null;
     }
 
@@ -299,6 +317,11 @@
      * Starts the process of determining the best matching service and maintaining a binding to it.
      */
     public void register() {
+        mHandler.sendMessage(PooledLambda.obtainMessage(ServiceWatcher::registerInternal,
+                ServiceWatcher.this));
+    }
+
+    private void registerInternal() {
         Preconditions.checkState(!mRegistered);
 
         mPackageMonitor.register(mContext, UserHandle.ALL, true, mHandler);
@@ -309,6 +332,8 @@
         mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, intentFilter, null,
                 mHandler);
 
+        // TODO: This makes the behavior of the class unpredictable as the caller needs
+        // to know the internal impl detail that calling register would pick the current user.
         mCurrentUserId = ActivityManager.getCurrentUser();
 
         mRegistered = true;
@@ -320,6 +345,11 @@
      * Stops the process of determining the best matching service and releases any binding.
      */
     public void unregister() {
+        mHandler.sendMessage(PooledLambda.obtainMessage(ServiceWatcher::unregisterInternal,
+                ServiceWatcher.this));
+    }
+
+    private void unregisterInternal() {
         Preconditions.checkState(mRegistered);
 
         mRegistered = false;
@@ -333,7 +363,7 @@
     private void onBestServiceChanged(boolean forceRebind) {
         Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
 
-        ServiceInfo bestServiceInfo = ServiceInfo.NONE;
+        BoundService bestServiceInfo = BoundService.NONE;
 
         if (mRegistered) {
             List<ResolveInfo> resolveInfos = mContext.getPackageManager().queryIntentServicesAsUser(
@@ -344,7 +374,7 @@
                 if (!mServiceCheckPredicate.test(resolveInfo)) {
                     continue;
                 }
-                ServiceInfo serviceInfo = new ServiceInfo(resolveInfo, mCurrentUserId);
+                BoundService serviceInfo = new BoundService(resolveInfo);
                 if (serviceInfo.compareTo(bestServiceInfo) > 0) {
                     bestServiceInfo = serviceInfo;
                 }
@@ -356,21 +386,22 @@
         }
     }
 
-    private void rebind(ServiceInfo newServiceInfo) {
+    private void rebind(BoundService newServiceInfo) {
         Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
 
-        if (!mTargetService.equals(ServiceInfo.NONE)) {
+        if (!mTargetService.equals(BoundService.NONE)) {
             if (D) {
                 Log.d(TAG, "[" + mIntent.getAction() + "] unbinding from " + mTargetService);
             }
 
             mContext.unbindService(this);
             onServiceDisconnected(mTargetService.component);
-            mTargetService = ServiceInfo.NONE;
+            mPendingBinds.remove(mTargetService.component);
+            mTargetService = BoundService.NONE;
         }
 
         mTargetService = newServiceInfo;
-        if (mTargetService.equals(ServiceInfo.NONE)) {
+        if (mTargetService.equals(BoundService.NONE)) {
             return;
         }
 
@@ -381,10 +412,12 @@
         Intent bindIntent = new Intent(mIntent).setComponent(mTargetService.component);
         if (!mContext.bindServiceAsUser(bindIntent, this,
                 BIND_AUTO_CREATE | BIND_NOT_FOREGROUND | BIND_NOT_VISIBLE,
-                mHandler, UserHandle.of(mTargetService.userId))) {
-            mTargetService = ServiceInfo.NONE;
+                mHandler, UserHandle.of(UserHandle.getUserId(mTargetService.uid)))) {
+            mTargetService = BoundService.NONE;
             Log.e(TAG, getLogPrefix() + " unexpected bind failure - retrying later");
             mHandler.postDelayed(() -> onBestServiceChanged(false), RETRY_DELAY_MS);
+        } else {
+            mPendingBinds.put(mTargetService.component, mTargetService);
         }
     }
 
@@ -397,10 +430,15 @@
             Log.d(TAG, getLogPrefix() + " connected to " + component.toShortString());
         }
 
+        final BoundService boundService = mPendingBinds.remove(component);
+        if (boundService == null) {
+            return;
+        }
+
         mBinder = binder;
         if (mOnBind != null) {
             try {
-                mOnBind.run(binder, component);
+                mOnBind.run(binder, boundService);
             } catch (RuntimeException | RemoteException e) {
                 // binders may propagate some specific non-RemoteExceptions from the other side
                 // through the binder as well - we cannot allow those to crash the system server
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
index de8823c..6366280 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
@@ -39,6 +39,7 @@
 import android.media.soundtrigger_middleware.SoundModel;
 import android.media.soundtrigger_middleware.SoundModelType;
 import android.media.soundtrigger_middleware.SoundTriggerModuleProperties;
+import android.os.HidlMemory;
 import android.os.HidlMemoryUtil;
 import android.os.ParcelFileDescriptor;
 
@@ -199,18 +200,7 @@
         hidlModel.header.type = aidl2hidlSoundModelType(aidlModel.type);
         hidlModel.header.uuid = aidl2hidlUuid(aidlModel.uuid);
         hidlModel.header.vendorUuid = aidl2hidlUuid(aidlModel.vendorUuid);
-
-        // Extract a dup of the underlying FileDescriptor out of aidlModel.data without changing
-        // the original.
-        FileDescriptor fd = new FileDescriptor();
-        try {
-            ParcelFileDescriptor dup = aidlModel.data.dup();
-            fd.setInt$(dup.detachFd());
-            hidlModel.data = HidlMemoryUtil.fileDescriptorToHidlMemory(fd, aidlModel.dataSize);
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-
+        hidlModel.data = parcelFileDescriptorToHidlMemory(aidlModel.data, aidlModel.dataSize);
         return hidlModel;
     }
 
@@ -425,4 +415,31 @@
         }
         return aidlCapabilities;
     }
+
+    /**
+     * Convert an AIDL representation of a shared memory block (ParcelFileDescriptor + size) to the
+     * HIDL representation (HidlMemory). Will not change the incoming data or any ownership
+     * semantics, but rather duplicate the underlying FD.
+     *
+     * @param data     The incoming memory block. May be null if dataSize is 0.
+     * @param dataSize The number of bytes in the block.
+     * @return A HidlMemory representation of the memory block. Will be non-null even for an empty
+     *         block.
+     */
+    private static @NonNull
+    HidlMemory parcelFileDescriptorToHidlMemory(@Nullable ParcelFileDescriptor data, int dataSize) {
+        if (dataSize > 0) {
+            // Extract a dup of the underlying FileDescriptor out of data.
+            FileDescriptor fd = new FileDescriptor();
+            try {
+                ParcelFileDescriptor dup = data.dup();
+                fd.setInt$(dup.detachFd());
+                return HidlMemoryUtil.fileDescriptorToHidlMemory(fd, dataSize);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        } else {
+            return HidlMemoryUtil.fileDescriptorToHidlMemory(null, 0);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java
index ebe9733..212f81f 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java
@@ -35,8 +35,7 @@
  * HAL whenever they expire.
  */
 public class SoundTriggerHw2Watchdog implements ISoundTriggerHw2 {
-    // TODO(b/166328980): Reduce this to 1000 as soon as HAL is fixed.
-    private static final long TIMEOUT_MS = 10000;
+    private static final long TIMEOUT_MS = 3000;
     private static final String TAG = "SoundTriggerHw2Watchdog";
 
     private final @NonNull
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ValidationUtil.java b/services/core/java/com/android/server/soundtrigger_middleware/ValidationUtil.java
index 43047d1..e05c468 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/ValidationUtil.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/ValidationUtil.java
@@ -62,7 +62,9 @@
         }
         validateUuid(model.uuid);
         validateUuid(model.vendorUuid);
-        Objects.requireNonNull(model.data);
+        if (model.dataSize > 0) {
+            Objects.requireNonNull(model.data);
+        }
     }
 
     static void validatePhraseModel(@Nullable PhraseSoundModel model) {
diff --git a/services/core/java/com/android/server/speech/Android.bp b/services/core/java/com/android/server/speech/Android.bp
index 379b075..5605349 100644
--- a/services/core/java/com/android/server/speech/Android.bp
+++ b/services/core/java/com/android/server/speech/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 filegroup {
     name: "services.speech-sources",
     srcs: ["java/**/*.java"],
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index a390df9..8ffbb0a 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -1336,7 +1336,7 @@
     }
 
     @Override
-    public void onNotificationClear(String pkg, String tag, int id, int userId, String key,
+    public void onNotificationClear(String pkg, int userId, String key,
             @NotificationStats.DismissalSurface int dismissalSurface,
             @NotificationStats.DismissalSentiment int dismissalSentiment,
             NotificationVisibility nv) {
@@ -1345,7 +1345,7 @@
         final int callingPid = Binder.getCallingPid();
         final long identity = Binder.clearCallingIdentity();
         try {
-            mNotificationDelegate.onNotificationClear(callingUid, callingPid, pkg, tag, id, userId,
+            mNotificationDelegate.onNotificationClear(callingUid, callingPid, pkg, userId,
                     key, dismissalSurface, dismissalSentiment, nv);
         } finally {
             Binder.restoreCallingIdentity(identity);
diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java
index 0087c0c..dedb3ac 100644
--- a/services/core/java/com/android/server/storage/StorageSessionController.java
+++ b/services/core/java/com/android/server/storage/StorageSessionController.java
@@ -32,6 +32,7 @@
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.os.UserHandle;
+import android.os.storage.StorageManager;
 import android.os.storage.StorageVolume;
 import android.os.storage.VolumeInfo;
 import android.provider.MediaStore;
@@ -162,22 +163,17 @@
      *
      * @return ANR dialog delay in milliseconds
      */
-    public long getAnrDelayMillis(String packageName, int uid)
+    public void notifyAnrDelayStarted(String packageName, int uid, int tid, int reason)
             throws ExternalStorageServiceException {
+        final int userId = UserHandle.getUserId(uid);
+        final StorageUserConnection connection;
         synchronized (mLock) {
-            int size = mConnections.size();
-            for (int i = 0; i < size; i++) {
-                int key = mConnections.keyAt(i);
-                StorageUserConnection connection = mConnections.get(key);
-                if (connection != null) {
-                    long delay = connection.getAnrDelayMillis(packageName, uid);
-                    if (delay > 0) {
-                        return delay;
-                    }
-                }
-            }
+            connection = mConnections.get(userId);
         }
-        return 0;
+
+        if (connection != null) {
+            connection.notifyAnrDelayStarted(packageName, uid, tid, reason);
+        }
     }
 
     /**
@@ -371,6 +367,60 @@
         return mExternalStorageServiceComponent;
     }
 
+    /**
+     * Notify the controller that an app with {@code uid} and {@code tid} is blocked on an IO
+     * request on {@code volumeUuid} for {@code reason}.
+     *
+     * This blocked state can be queried with {@link #isAppIoBlocked}
+     *
+     * @hide
+     */
+    public void notifyAppIoBlocked(String volumeUuid, int uid, int tid,
+            @StorageManager.AppIoBlockedReason int reason) {
+        final int userId = UserHandle.getUserId(uid);
+        final StorageUserConnection connection;
+        synchronized (mLock) {
+            connection = mConnections.get(userId);
+        }
+
+        if (connection != null) {
+            connection.notifyAppIoBlocked(volumeUuid, uid, tid, reason);
+        }
+    }
+
+    /**
+     * Notify the controller that an app with {@code uid} and {@code tid} has resmed a previously
+     * blocked IO request on {@code volumeUuid} for {@code reason}.
+     *
+     * All app IO will be automatically marked as unblocked if {@code volumeUuid} is unmounted.
+     */
+    public void notifyAppIoResumed(String volumeUuid, int uid, int tid,
+            @StorageManager.AppIoBlockedReason int reason) {
+        final int userId = UserHandle.getUserId(uid);
+        final StorageUserConnection connection;
+        synchronized (mLock) {
+            connection = mConnections.get(userId);
+        }
+
+        if (connection != null) {
+            connection.notifyAppIoResumed(volumeUuid, uid, tid, reason);
+        }
+    }
+
+    /** Returns {@code true} if {@code uid} is blocked on IO, {@code false} otherwise */
+    public boolean isAppIoBlocked(int uid) {
+        final int userId = UserHandle.getUserId(uid);
+        final StorageUserConnection connection;
+        synchronized (mLock) {
+            connection = mConnections.get(userId);
+        }
+
+        if (connection != null) {
+            return connection.isAppIoBlocked(uid);
+        }
+        return false;
+    }
+
     private void killExternalStorageService(int userId) {
         IActivityManager am = ActivityManager.getService();
         try {
diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java
index 709d558..d2b05c0 100644
--- a/services/core/java/com/android/server/storage/StorageUserConnection.java
+++ b/services/core/java/com/android/server/storage/StorageUserConnection.java
@@ -16,7 +16,6 @@
 
 package com.android.server.storage;
 
-import static android.service.storage.ExternalStorageService.EXTRA_ANR_TIMEOUT_MS;
 import static android.service.storage.ExternalStorageService.EXTRA_ERROR;
 import static android.service.storage.ExternalStorageService.FLAG_SESSION_ATTRIBUTE_INDEXABLE;
 import static android.service.storage.ExternalStorageService.FLAG_SESSION_TYPE_FUSE;
@@ -38,10 +37,12 @@
 import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.storage.StorageManager;
 import android.os.storage.StorageManagerInternal;
 import android.os.storage.StorageVolume;
 import android.service.storage.ExternalStorageService;
 import android.service.storage.IExternalStorageService;
+import android.util.ArraySet;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
@@ -73,6 +74,7 @@
     private final StorageSessionController mSessionController;
     private final ActiveConnection mActiveConnection = new ActiveConnection();
     @GuardedBy("mLock") private final Map<String, Session> mSessions = new HashMap<>();
+    @GuardedBy("mLock") private final Set<Integer> mUidsBlockedOnIo = new ArraySet<>();
     private final HandlerThread mHandlerThread;
 
     public StorageUserConnection(Context context, int userId, StorageSessionController controller) {
@@ -148,17 +150,13 @@
      *
      * @return ANR dialog delay in milliseconds
      */
-    public long getAnrDelayMillis(String packageName, int uid)
+    public void notifyAnrDelayStarted(String packageName, int uid, int tid, int reason)
             throws ExternalStorageServiceException {
         synchronized (mSessionsLock) {
             for (String sessionId : mSessions.keySet()) {
-                long delay = mActiveConnection.getAnrDelayMillis(packageName, uid);
-                if (delay > 0) {
-                    return delay;
-                }
+                mActiveConnection.notifyAnrDelayStarted(packageName, uid, tid, reason);
             }
         }
-        return 0;
     }
 
     /**
@@ -170,6 +168,7 @@
      **/
     public Session removeSession(String sessionId) {
         synchronized (mSessionsLock) {
+            mUidsBlockedOnIo.clear();
             return mSessions.remove(sessionId);
         }
     }
@@ -232,6 +231,41 @@
         }
     }
 
+    /**
+     * Notify the controller that an app with {@code uid} and {@code tid} is blocked on an IO
+     * request on {@code volumeUuid} for {@code reason}.
+     *
+     * This blocked state can be queried with {@link #isAppIoBlocked}
+     *
+     * @hide
+     */
+    public void notifyAppIoBlocked(String volumeUuid, int uid, int tid,
+            @StorageManager.AppIoBlockedReason int reason) {
+        synchronized (mSessionsLock) {
+            mUidsBlockedOnIo.add(uid);
+        }
+    }
+
+    /**
+     * Notify the connection that an app with {@code uid} and {@code tid} has resmed a previously
+     * blocked IO request on {@code volumeUuid} for {@code reason}.
+     *
+     * All app IO will be automatically marked as unblocked if {@code volumeUuid} is unmounted.
+     */
+    public void notifyAppIoResumed(String volumeUuid, int uid, int tid,
+            @StorageManager.AppIoBlockedReason int reason) {
+        synchronized (mSessionsLock) {
+            mUidsBlockedOnIo.remove(uid);
+        }
+    }
+
+    /** Returns {@code true} if {@code uid} is blocked on IO, {@code false} otherwise */
+    public boolean isAppIoBlocked(int uid) {
+        synchronized (mSessionsLock) {
+            return mUidsBlockedOnIo.contains(uid);
+        }
+    }
+
     @FunctionalInterface
     interface AsyncStorageServiceCall {
         void run(@NonNull IExternalStorageService service, RemoteCallback callback) throws
@@ -253,9 +287,6 @@
         @GuardedBy("mLock")
         private final ArrayList<CompletableFuture<Void>> mOutstandingOps = new ArrayList<>();
 
-        @GuardedBy("mLock")
-        private final ArrayList<CompletableFuture<Long>> mOutstandingTimeoutOps = new ArrayList<>();
-
         @Override
         public void close() {
             ServiceConnection oldConnection = null;
@@ -272,9 +303,6 @@
                 for (CompletableFuture<Void> op : mOutstandingOps) {
                     op.cancel(true);
                 }
-                for (CompletableFuture<Long> op : mOutstandingTimeoutOps) {
-                    op.cancel(true);
-                }
                 mOutstandingOps.clear();
             }
 
@@ -297,15 +325,6 @@
                     DEFAULT_REMOTE_TIMEOUT_SECONDS);
         }
 
-        private long waitForAsyncLong(AsyncStorageServiceCall asyncCall) throws Exception {
-            CompletableFuture<Long> opFuture = new CompletableFuture<>();
-            RemoteCallback callback =
-                    new RemoteCallback(result -> setTimeoutResult(result, opFuture));
-
-            return waitForAsync(asyncCall, callback, opFuture, mOutstandingTimeoutOps,
-                    1 /* timeoutSeconds */);
-        }
-
         private <T> T waitForAsync(AsyncStorageServiceCall asyncCall, RemoteCallback callback,
                 CompletableFuture<T> opFuture, ArrayList<CompletableFuture<T>> outstandingOps,
                 long timeoutSeconds) throws Exception {
@@ -380,27 +399,17 @@
             }
         }
 
-        public long getAnrDelayMillis(String packgeName, int uid)
+        public void notifyAnrDelayStarted(String packgeName, int uid, int tid, int reason)
                 throws ExternalStorageServiceException {
             try {
-                return waitForAsyncLong((service, callback) ->
-                        service.getAnrDelayMillis(packgeName, uid, callback));
+                waitForAsyncVoid((service, callback) ->
+                        service.notifyAnrDelayStarted(packgeName, uid, tid, reason, callback));
             } catch (Exception e) {
-                throw new ExternalStorageServiceException("Failed to notify app not responding: "
+                throw new ExternalStorageServiceException("Failed to notify ANR delay started: "
                         + packgeName, e);
             }
         }
 
-        private void setTimeoutResult(Bundle result, CompletableFuture<Long> future) {
-            ParcelableException ex = result.getParcelable(EXTRA_ERROR);
-            if (ex != null) {
-                future.completeExceptionally(ex);
-            } else {
-                long timeoutMs = result.getLong(EXTRA_ANR_TIMEOUT_MS);
-                future.complete(timeoutMs);
-            }
-        }
-
         private void setResult(Bundle result, CompletableFuture<Void> future) {
             ParcelableException ex = result.getParcelable(EXTRA_ERROR);
             if (ex != null) {
diff --git a/services/core/java/com/android/server/telecom/InternalServiceRepository.java b/services/core/java/com/android/server/telecom/InternalServiceRepository.java
index 76ea5c7..bd1746d 100644
--- a/services/core/java/com/android/server/telecom/InternalServiceRepository.java
+++ b/services/core/java/com/android/server/telecom/InternalServiceRepository.java
@@ -16,6 +16,8 @@
 
 package com.android.server.telecom;
 
+import static android.os.PowerWhitelistManager.REASON_UNKNOWN;
+
 import android.content.Context;
 import android.os.Binder;
 import android.os.Process;
@@ -38,7 +40,7 @@
         public void exemptAppTemporarilyForEvent(String packageName, long duration, int userHandle,
                 String reason) {
             mDeviceIdleController.addPowerSaveTempWhitelistApp(Process.myUid(), packageName,
-                    duration, userHandle, true /*sync*/, reason);
+                    duration, userHandle, true /*sync*/, REASON_UNKNOWN, reason);
         }
     };
 
diff --git a/services/core/java/com/android/server/timedetector/DeviceConfig.java b/services/core/java/com/android/server/timedetector/DeviceConfig.java
deleted file mode 100644
index 7b9ad0f..0000000
--- a/services/core/java/com/android/server/timedetector/DeviceConfig.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * 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.timedetector;
-
-import static android.provider.DeviceConfig.NAMESPACE_SYSTEM_TIME;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.StringDef;
-
-import java.time.Duration;
-import java.util.concurrent.Executor;
-
-/**
- * A helper class for reading / monitoring the {@link
- * android.provider.DeviceConfig#NAMESPACE_SYSTEM_TIME} namespace for server-configured flags.
- */
-public final class DeviceConfig {
-
-    /**
-     * An annotation used to indicate when a {@link
-     * android.provider.DeviceConfig#NAMESPACE_SYSTEM_TIME} key is required.
-     *
-     * <p>Note that the com.android.geotz module deployment of the Offline LocationTimeZoneProvider
-     * also shares the {@link android.provider.DeviceConfig#NAMESPACE_SYSTEM_TIME}, and uses the
-     * prefix "geotz_" on all of its key strings.
-     */
-    @StringDef(prefix = "KEY_", value = {
-            KEY_FORCE_LOCATION_TIME_ZONE_DETECTION_ENABLED,
-            KEY_LOCATION_TIME_ZONE_DETECTION_ENABLED_DEFAULT,
-            KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS,
-            KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS,
-            KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS,
-    })
-    @interface DeviceConfigKey {}
-
-    /**
-     * The key to force location time zone detection on for a device. Only intended for use during
-     * release testing with droidfooders. The user can still disable the feature by turning off the
-     * master location switch, or disabling automatic time zone detection.
-     */
-    @DeviceConfigKey
-    public static final String KEY_FORCE_LOCATION_TIME_ZONE_DETECTION_ENABLED =
-            "force_location_time_zone_detection_enabled";
-
-    /**
-     * The key for the default value used to determine whether location time zone detection is
-     * enabled when the user hasn't explicitly set it yet.
-     */
-    @DeviceConfigKey
-    public static final String KEY_LOCATION_TIME_ZONE_DETECTION_ENABLED_DEFAULT =
-            "location_time_zone_detection_enabled_default";
-
-    /**
-     * The key for the minimum delay after location time zone detection has been enabled before the
-     * location time zone manager can report it is uncertain about the time zone.
-     */
-    @DeviceConfigKey
-    public static final String KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS =
-            "location_time_zone_detection_uncertainty_delay_millis";
-
-    /**
-     * The key for the timeout passed to a location time zone provider that tells it how long it has
-     * to provide an explicit first suggestion without being declared uncertain.
-     */
-    @DeviceConfigKey
-    public static final String KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS =
-            "ltpz_init_timeout_millis";
-
-    /**
-     * The key for the extra time added to {@link
-     * #KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS} by the location time zone
-     * manager before the location time zone provider will actually be declared uncertain.
-     */
-    @DeviceConfigKey
-    public static final String KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS =
-            "ltpz_init_timeout_fuzz_millis";
-
-    /** Creates an instance. */
-    public DeviceConfig() {}
-
-    /** Adds a listener for the system_time namespace. */
-    public void addListener(
-            @NonNull Executor handlerExecutor, @NonNull Runnable listener) {
-        android.provider.DeviceConfig.addOnPropertiesChangedListener(
-                NAMESPACE_SYSTEM_TIME,
-                handlerExecutor,
-                properties -> listener.run());
-    }
-
-    /**
-     * Returns a boolean value from {@link android.provider.DeviceConfig} from the system_time
-     * namespace, or {@code defaultValue} if there is no explicit value set.
-     */
-    public boolean getBoolean(@DeviceConfigKey String key, boolean defaultValue) {
-        return android.provider.DeviceConfig.getBoolean(NAMESPACE_SYSTEM_TIME, key, defaultValue);
-    }
-
-    /**
-     * Returns a positive duration from {@link android.provider.DeviceConfig} from the system_time
-     * namespace, or {@code defaultValue} if there is no explicit value set.
-     */
-    @Nullable
-    public Duration getDurationFromMillis(
-            @DeviceConfigKey String key, @Nullable Duration defaultValue) {
-        long deviceConfigValue =
-                android.provider.DeviceConfig.getLong(NAMESPACE_SYSTEM_TIME, key, -1);
-        if (deviceConfigValue < 0) {
-            return defaultValue;
-        }
-        return Duration.ofMillis(deviceConfigValue);
-    }
-}
diff --git a/services/core/java/com/android/server/timedetector/ServerFlags.java b/services/core/java/com/android/server/timedetector/ServerFlags.java
new file mode 100644
index 0000000..8819b37
--- /dev/null
+++ b/services/core/java/com/android/server/timedetector/ServerFlags.java
@@ -0,0 +1,238 @@
+/*
+ * 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.timedetector;
+
+import static android.provider.DeviceConfig.NAMESPACE_SYSTEM_TIME;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringDef;
+import android.content.Context;
+import android.provider.DeviceConfig;
+import android.util.ArrayMap;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.timezonedetector.ConfigurationChangeListener;
+import com.android.server.timezonedetector.ServiceConfigAccessor;
+
+import java.time.Duration;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * A helper class for reading / monitoring the {@link DeviceConfig#NAMESPACE_SYSTEM_TIME} namespace
+ * for server-configured flags.
+ */
+public final class ServerFlags {
+
+    private static final Optional<Boolean> OPTIONAL_TRUE = Optional.of(true);
+    private static final Optional<Boolean> OPTIONAL_FALSE = Optional.of(false);
+
+    /**
+     * An annotation used to indicate when a {@link DeviceConfig#NAMESPACE_SYSTEM_TIME} key is
+     * required.
+     *
+     * <p>Note that the com.android.geotz module deployment of the Offline LocationTimeZoneProvider
+     * also shares the {@link DeviceConfig#NAMESPACE_SYSTEM_TIME}, and uses the
+     * prefix "geotz_" on all of its key strings.
+     */
+    @StringDef(prefix = "KEY_", value = {
+            KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED,
+            KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE,
+            KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE,
+            KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS,
+            KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS,
+            KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS,
+            KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE,
+            KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT,
+    })
+    @interface DeviceConfigKey {}
+
+    /**
+     * Controls whether the location time zone manager service will started. Only observed if
+     * the device build is configured to support location-based time zone detection. See
+     * {@link ServiceConfigAccessor#isGeoTimeZoneDetectionFeatureSupportedInConfig()} and {@link
+     * ServiceConfigAccessor#isGeoTimeZoneDetectionFeatureSupported()}.
+     */
+    @DeviceConfigKey
+    public static final String KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED =
+            "location_time_zone_detection_feature_supported";
+
+    /**
+     * The key for the server flag that can override the device config for whether the primary
+     * location time zone provider is enabled or disabled.
+     */
+    @DeviceConfigKey
+    public static final String KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE =
+            "primary_location_time_zone_provider_enabled_override";
+
+    /**
+     * The key for the server flag that can override the device config for whether the secondary
+     * location time zone provider is enabled or disabled.
+     */
+    @DeviceConfigKey
+    public static final String KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE =
+            "secondary_location_time_zone_provider_enabled_override";
+
+    /**
+     * The key for the minimum delay after location time zone detection has been enabled before the
+     * location time zone manager can report it is uncertain about the time zone.
+     */
+    @DeviceConfigKey
+    public static final String KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS =
+            "location_time_zone_detection_uncertainty_delay_millis";
+
+    /**
+     * The key for the timeout passed to a location time zone provider that tells it how long it has
+     * to provide an explicit first suggestion without being declared uncertain.
+     */
+    @DeviceConfigKey
+    public static final String KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS =
+            "ltpz_init_timeout_millis";
+
+    /**
+     * The key for the extra time added to {@link
+     * #KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS} by the location time zone
+     * manager before the location time zone provider will actually be declared uncertain.
+     */
+    @DeviceConfigKey
+    public static final String KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS =
+            "ltpz_init_timeout_fuzz_millis";
+
+    /**
+     * The key for the server flag that can override location time zone detection being enabled for
+     * a user. Only intended for use during release testing with droidfooders. The user can still
+     * disable the feature by turning off the master location switch, or by disabling automatic time
+     * zone detection.
+     */
+    @DeviceConfigKey
+    public static final String KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE =
+            "location_time_zone_detection_setting_enabled_override";
+
+    /**
+     * The key for the default value used to determine whether location time zone detection is
+     * enabled when the user hasn't explicitly set it yet.
+     */
+    @DeviceConfigKey
+    public static final String KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT =
+            "location_time_zone_detection_setting_enabled_default";
+
+    @GuardedBy("mListeners")
+    private final ArrayMap<ConfigurationChangeListener, Set<String>> mListeners = new ArrayMap<>();
+
+    private static final Object SLOCK = new Object();
+
+    @GuardedBy("SLOCK")
+    @Nullable
+    private static ServerFlags sInstance;
+
+    private ServerFlags(Context context) {
+        DeviceConfig.addOnPropertiesChangedListener(
+                NAMESPACE_SYSTEM_TIME,
+                context.getMainExecutor(),
+                this::handlePropertiesChanged);
+    }
+
+    /** Returns the singleton instance. */
+    public static ServerFlags getInstance(Context context) {
+        synchronized (SLOCK) {
+            if (sInstance == null) {
+                sInstance = new ServerFlags(context);
+            }
+            return sInstance;
+        }
+    }
+
+    private void handlePropertiesChanged(@NonNull DeviceConfig.Properties properties) {
+        synchronized (mListeners) {
+            for (Map.Entry<ConfigurationChangeListener, Set<String>> listenerEntry
+                    : mListeners.entrySet()) {
+                if (intersects(listenerEntry.getValue(), properties.getKeyset())) {
+                    listenerEntry.getKey().onChange();
+                }
+            }
+        }
+    }
+
+    private static boolean intersects(@NonNull Set<String> one, @NonNull Set<String> two) {
+        for (String toFind : one) {
+            if (two.contains(toFind)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Adds a listener for the system_time namespace that will trigger if any of the specified keys
+     * change. Listener callbacks are delivered on the main looper thread.
+     *
+     * <p>Note: Only for use by long-lived objects like other singletons. There is deliberately no
+     * associated remove method.
+     */
+    public void addListener(@NonNull ConfigurationChangeListener listener,
+            @NonNull Set<String> keys) {
+        Objects.requireNonNull(listener);
+        Objects.requireNonNull(keys);
+
+        synchronized (mListeners) {
+            mListeners.put(listener, keys);
+        }
+    }
+
+    /**
+     * Returns an optional boolean value from {@link DeviceConfig} from the system_time
+     * namespace, returns {@link Optional#empty()} if there is no explicit value set.
+     */
+    @NonNull
+    public Optional<Boolean> getOptionalBoolean(@DeviceConfigKey String key) {
+        String value = DeviceConfig.getProperty(NAMESPACE_SYSTEM_TIME, key);
+        return parseOptionalBoolean(value);
+    }
+
+    @NonNull
+    private static Optional<Boolean> parseOptionalBoolean(@Nullable String value) {
+        if (value == null) {
+            return Optional.empty();
+        } else {
+            return Boolean.parseBoolean(value) ? OPTIONAL_TRUE : OPTIONAL_FALSE;
+        }
+    }
+
+    /**
+     * Returns a boolean value from {@link DeviceConfig} from the system_time
+     * namespace, or {@code defaultValue} if there is no explicit value set.
+     */
+    public boolean getBoolean(@DeviceConfigKey String key, boolean defaultValue) {
+        return DeviceConfig.getBoolean(NAMESPACE_SYSTEM_TIME, key, defaultValue);
+    }
+
+    /**
+     * Returns a positive duration from {@link DeviceConfig} from the system_time
+     * namespace, or {@code defaultValue} if there is no explicit value set.
+     */
+    @Nullable
+    public Duration getDurationFromMillis(
+            @DeviceConfigKey String key, @Nullable Duration defaultValue) {
+        long deviceConfigValue = DeviceConfig.getLong(NAMESPACE_SYSTEM_TIME, key, -1);
+        if (deviceConfigValue < 0) {
+            return defaultValue;
+        }
+        return Duration.ofMillis(deviceConfigValue);
+    }
+}
diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java b/services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java
index 4c7b1f3..aa8ad37 100644
--- a/services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java
+++ b/services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java
@@ -17,10 +17,11 @@
 package com.android.server.timezonedetector;
 
 /**
- * A listener used to receive notification that time zone configuration has changed.
+ * A listener used to receive notification that configuration has / may have changed (depending on
+ * the usecase).
  */
 @FunctionalInterface
 public interface ConfigurationChangeListener {
-    /** Called when the current user or a configuration value has changed. */
+    /** Called when the configuration may have changed. */
     void onChange();
 }
diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
index 1f73977..3ae9d64 100644
--- a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
+++ b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
@@ -33,26 +33,27 @@
 import java.util.Objects;
 
 /**
- * Holds all configuration values that affect time zone behavior and some associated logic, e.g.
- * {@link #getAutoDetectionEnabledBehavior()}, {@link #getGeoDetectionEnabledBehavior()} and {@link
- * #createCapabilitiesAndConfig()}.
+ * Holds configuration values that affect user-facing time zone behavior and some associated logic.
+ * Some configuration is global, some is user scoped, but this class deliberately doesn't make a
+ * distinction for simplicity.
  */
 public final class ConfigurationInternal {
 
-    private final @UserIdInt int mUserId;
-    private final boolean mUserConfigAllowed;
     private final boolean mAutoDetectionSupported;
     private final boolean mGeoDetectionSupported;
     private final boolean mAutoDetectionEnabled;
+    private final @UserIdInt int mUserId;
+    private final boolean mUserConfigAllowed;
     private final boolean mLocationEnabled;
     private final boolean mGeoDetectionEnabled;
 
     private ConfigurationInternal(Builder builder) {
-        mUserId = builder.mUserId;
-        mUserConfigAllowed = builder.mUserConfigAllowed;
         mAutoDetectionSupported = builder.mAutoDetectionSupported;
         mGeoDetectionSupported = builder.mGeoDetectionSupported;
         mAutoDetectionEnabled = builder.mAutoDetectionEnabled;
+
+        mUserId = builder.mUserId;
+        mUserConfigAllowed = builder.mUserConfigAllowed;
         mLocationEnabled = builder.mLocationEnabled;
         mGeoDetectionEnabled = builder.mGeoDetectionEnabled;
         // if mGeoDetectionSupported then mAutoDetectionSupported, i.e. mGeoDetectionSupported
@@ -60,22 +61,6 @@
         Preconditions.checkState(mAutoDetectionSupported || !mGeoDetectionSupported);
     }
 
-    /** Returns the ID of the user this configuration is associated with. */
-    public @UserIdInt int getUserId() {
-        return mUserId;
-    }
-
-    /** Returns the handle of the user this configuration is associated with. */
-    @NonNull
-    public UserHandle getUserHandle() {
-        return UserHandle.of(mUserId);
-    }
-
-    /** Returns true if the user allowed to modify time zone configuration. */
-    public boolean isUserConfigAllowed() {
-        return mUserConfigAllowed;
-    }
-
     /** Returns true if the device supports any form of auto time zone detection. */
     public boolean isAutoDetectionSupported() {
         return mAutoDetectionSupported;
@@ -98,6 +83,22 @@
         return mAutoDetectionSupported && mAutoDetectionEnabled;
     }
 
+    /** Returns the ID of the user this configuration is associated with. */
+    public @UserIdInt int getUserId() {
+        return mUserId;
+    }
+
+    /** Returns the handle of the user this configuration is associated with. */
+    @NonNull
+    public UserHandle getUserHandle() {
+        return UserHandle.of(mUserId);
+    }
+
+    /** Returns true if the user allowed to modify time zone configuration. */
+    public boolean isUserConfigAllowed() {
+        return mUserConfigAllowed;
+    }
+
     /** Returns true if user's location can be used generally. */
     public boolean isLocationEnabled() {
         return mLocationEnabled;
@@ -283,7 +284,7 @@
         /**
          * Sets whether any form of automatic time zone detection is supported on this device.
          */
-        public Builder setAutoDetectionSupported(boolean supported) {
+        public Builder setAutoDetectionFeatureSupported(boolean supported) {
             mAutoDetectionSupported = supported;
             return this;
         }
@@ -291,7 +292,7 @@
         /**
          * Sets whether geolocation time zone detection is supported on this device.
          */
-        public Builder setGeoDetectionSupported(boolean supported) {
+        public Builder setGeoDetectionFeatureSupported(boolean supported) {
             mGeoDetectionSupported = supported;
             return this;
         }
diff --git a/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java b/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java
index f52b9b1..e3caae94 100644
--- a/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java
@@ -31,9 +31,7 @@
 import android.content.IntentFilter;
 import android.database.ContentObserver;
 import android.location.LocationManager;
-import android.net.ConnectivityManager;
 import android.os.Handler;
-import android.os.HandlerExecutor;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -42,10 +40,9 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.server.LocalServices;
-import com.android.server.timedetector.DeviceConfig;
 
 import java.util.Objects;
-import java.util.concurrent.Executor;
+import java.util.Optional;
 
 /**
  * The real implementation of {@link TimeZoneDetectorStrategyImpl.Environment}.
@@ -59,8 +56,7 @@
     @NonNull private final Handler mHandler;
     @NonNull private final ContentResolver mCr;
     @NonNull private final UserManager mUserManager;
-    @NonNull private final DeviceConfig mDeviceConfig;
-    @NonNull private final boolean mGeoDetectionSupported;
+    @NonNull private final ServiceConfigAccessor mServiceConfigAccessor;
     @NonNull private final LocationManager mLocationManager;
 
     // @NonNull after setConfigChangeListener() is called.
@@ -68,17 +64,16 @@
     private ConfigurationChangeListener mConfigChangeListener;
 
     EnvironmentImpl(@NonNull Context context, @NonNull Handler handler,
-            @NonNull DeviceConfig deviceConfig, boolean geoDetectionSupported) {
+            @NonNull ServiceConfigAccessor serviceConfigAccessor) {
         mContext = Objects.requireNonNull(context);
         mHandler = Objects.requireNonNull(handler);
-        Executor handlerExecutor = new HandlerExecutor(mHandler);
         mCr = context.getContentResolver();
         mUserManager = context.getSystemService(UserManager.class);
         mLocationManager = context.getSystemService(LocationManager.class);
-        mDeviceConfig = deviceConfig;
-        mGeoDetectionSupported = geoDetectionSupported;
+        mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor);
 
-        // Wire up the change listeners. All invocations are performed on the mHandler thread.
+        // Wire up the config change listeners. All invocations are performed on the mHandler
+        // thread.
 
         // Listen for the user changing / the user's location mode changing.
         IntentFilter filter = new IntentFilter();
@@ -112,13 +107,6 @@
                         handleConfigChangeOnHandlerThread();
                     }
                 }, UserHandle.USER_ALL);
-
-        // Add async callbacks for changes to server-side flags: some of the flags affect device /
-        // user config. All changes can be treated like a config change. If flags that affect config
-        // haven't changed then call will be a no-op.
-        mDeviceConfig.addListener(
-                handlerExecutor,
-                this::handleConfigChangeOnHandlerThread);
     }
 
     private void handleConfigChangeOnHandlerThread() {
@@ -140,10 +128,12 @@
     @Override
     public ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) {
         return new ConfigurationInternal.Builder(userId)
-                .setUserConfigAllowed(isUserConfigAllowed(userId))
-                .setAutoDetectionSupported(isAutoDetectionSupported())
-                .setGeoDetectionSupported(isGeoDetectionSupported())
+                .setAutoDetectionFeatureSupported(
+                        mServiceConfigAccessor.isAutoDetectionFeatureSupported())
+                .setGeoDetectionFeatureSupported(
+                        mServiceConfigAccessor.isGeoTimeZoneDetectionFeatureSupported())
                 .setAutoDetectionEnabled(isAutoDetectionEnabled())
+                .setUserConfigAllowed(isUserConfigAllowed(userId))
                 .setLocationEnabled(isLocationEnabled(userId))
                 .setGeoDetectionEnabled(isGeoDetectionEnabled(userId))
                 .build();
@@ -186,18 +176,19 @@
         // time zone detection: if we wrote it down then we'd set the value explicitly, which would
         // prevent detecting "default" later. That might influence what happens on later releases
         // that support new types of auto detection on the same hardware.
-        if (isAutoDetectionSupported()) {
+        if (mServiceConfigAccessor.isAutoDetectionFeatureSupported()) {
             final boolean autoDetectionEnabled = configuration.isAutoDetectionEnabled();
             setAutoDetectionEnabledIfRequired(autoDetectionEnabled);
 
-            // Avoid writing the geo detection enabled setting for devices that do not support geo
-            // time zone detection: if we wrote it down then we'd set the value explicitly, which
-            // would prevent detecting "default" later. That might influence what happens on later
-            // releases that support geo detection on the same hardware.
-            // Also avoid writing the geo detection enabled setting for devices that are currently
-            // force-enabled: otherwise we might overwrite a droidfood user's real setting
-            // permanently.
-            if (isGeoDetectionSupported() && !isGeoDetectionForceEnabled()) {
+            // Avoid writing the geo detection enabled setting for devices with settings that
+            // are currently overridden by server flags: otherwise we might overwrite a droidfood
+            // user's real setting permanently.
+            // Also avoid writing the geo detection enabled setting for devices that do not support
+            // geo time zone detection: if we wrote it down then we'd set the value explicitly,
+            // which would prevent detecting "default" later. That might influence what happens on
+            // later releases that start to support geo detection on the same hardware.
+            if (!mServiceConfigAccessor.getGeoDetectionSettingEnabledOverride().isPresent()
+                    && mServiceConfigAccessor.isGeoTimeZoneDetectionFeatureSupported()) {
                 final boolean geoTzDetectionEnabled = configuration.isGeoDetectionEnabled();
                 setGeoDetectionEnabledIfRequired(userId, geoTzDetectionEnabled);
             }
@@ -209,14 +200,6 @@
         return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME, userHandle);
     }
 
-    private boolean isAutoDetectionSupported() {
-        return deviceHasTelephonyNetwork() || isGeoDetectionSupported();
-    }
-
-    private boolean isGeoDetectionSupported() {
-        return mGeoDetectionSupported;
-    }
-
     private boolean isAutoDetectionEnabled() {
         return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0;
     }
@@ -237,24 +220,20 @@
 
     private boolean isGeoDetectionEnabled(@UserIdInt int userId) {
         // We may never use this, but it gives us a way to force location-based time zone detection
-        // on for testers (where their other settings allow).
-        boolean forceEnabled = isGeoDetectionForceEnabled();
-        if (forceEnabled) {
-            return true;
+        // on/off for testers (but only where their other settings would allow them to turn it on
+        // for themselves).
+        Optional<Boolean> override = mServiceConfigAccessor.getGeoDetectionSettingEnabledOverride();
+        if (override.isPresent()) {
+            return override.get();
         }
 
-        final boolean geoDetectionEnabledByDefault = mDeviceConfig.getBoolean(
-                DeviceConfig.KEY_LOCATION_TIME_ZONE_DETECTION_ENABLED_DEFAULT, false);
+        final boolean geoDetectionEnabledByDefault =
+                mServiceConfigAccessor.isGeoDetectionEnabledForUsersByDefault();
         return Settings.Secure.getIntForUser(mCr,
                 Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED,
                 (geoDetectionEnabledByDefault ? 1 : 0) /* defaultValue */, userId) != 0;
     }
 
-    private boolean isGeoDetectionForceEnabled() {
-        return mDeviceConfig.getBoolean(
-                DeviceConfig.KEY_FORCE_LOCATION_TIME_ZONE_DETECTION_ENABLED, false);
-    }
-
     private void setGeoDetectionEnabledIfRequired(@UserIdInt int userId, boolean enabled) {
         // See comment in setAutoDetectionEnabledIfRequired. http://b/171953500
         if (isGeoDetectionEnabled(userId) != enabled) {
@@ -262,10 +241,4 @@
                     enabled ? 1 : 0, userId);
         }
     }
-
-    private boolean deviceHasTelephonyNetwork() {
-        // TODO b/150583524 Avoid the use of a deprecated API.
-        return mContext.getSystemService(ConnectivityManager.class)
-                .isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
-    }
 }
diff --git a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
new file mode 100644
index 0000000..86c32f8
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
@@ -0,0 +1,249 @@
+/*
+ * 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.timezonedetector;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.os.SystemProperties;
+import android.util.ArraySet;
+
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.timedetector.ServerFlags;
+
+import java.time.Duration;
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * A singleton that provides access to service configuration for time zone detection. This hides how
+ * configuration is split between static, compile-time config and dynamic, server-pushed flags. It
+ * provides a rudimentary mechanism to signal when values have changed.
+ */
+public final class ServiceConfigAccessor {
+
+    private static final Set<String> SERVER_FLAGS_KEYS_TO_WATCH = Collections.unmodifiableSet(
+            new ArraySet<>(new String[] {
+                    ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED,
+                    ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT,
+                    ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE,
+                    ServerFlags.KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE,
+                    ServerFlags.KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE,
+                    ServerFlags.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS,
+                    ServerFlags.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS,
+                    ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS
+            }));
+
+    // TODO(b/179488561): Put this back to 5 minutes when primary provider is fully implemented
+    private static final Duration DEFAULT_PROVIDER_INITIALIZATION_TIMEOUT = Duration.ofMinutes(1);
+    // TODO(b/179488561): Put this back to 1 minute when primary provider is fully implemented
+    private static final Duration DEFAULT_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ =
+            Duration.ofSeconds(20);
+    private static final Duration DEFAULT_PROVIDER_UNCERTAINTY_DELAY = Duration.ofMinutes(5);
+
+    private static final Object SLOCK = new Object();
+
+    /** The singleton instance. Initialized once in {@link #getInstance(Context)}. */
+    @GuardedBy("SLOCK")
+    @Nullable
+    private static ServiceConfigAccessor sInstance;
+
+    @NonNull private final Context mContext;
+
+    /**
+     * An ultimate "feature switch" for location-based time zone detection. If this is
+     * {@code false}, the device cannot support the feature without a config change or a reboot:
+     * This affects what services are started on boot to minimize expense when the feature is not
+     * wanted.
+     */
+    private final boolean mGeoDetectionFeatureSupportedInConfig;
+
+    @NonNull private final ServerFlags mServerFlags;
+
+    private ServiceConfigAccessor(@NonNull Context context) {
+        mContext = Objects.requireNonNull(context);
+
+        // The config value is expected to be the main feature flag. Platform developers can also
+        // force enable the feature using a persistent system property. Because system properties
+        // can change, this value is cached and only changes on reboot.
+        mGeoDetectionFeatureSupportedInConfig = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_enableGeolocationTimeZoneDetection)
+                || SystemProperties.getBoolean(
+                "persist.sys.location_time_zone_detection_feature_supported", false);
+
+        mServerFlags = ServerFlags.getInstance(mContext);
+    }
+
+    /** Returns the singleton instance. */
+    public static ServiceConfigAccessor getInstance(Context context) {
+        synchronized (SLOCK) {
+            if (sInstance == null) {
+                sInstance = new ServiceConfigAccessor(context);
+            }
+            return sInstance;
+        }
+    }
+
+    /**
+     * Adds a listener that will be called server flags related to this class change. The callbacks
+     * are delivered on the main looper thread.
+     *
+     * <p>Note: Only for use by long-lived objects. There is deliberately no associated remove
+     * method.
+     */
+    public void addListener(@NonNull ConfigurationChangeListener listener) {
+        mServerFlags.addListener(listener, SERVER_FLAGS_KEYS_TO_WATCH);
+    }
+
+    /** Returns {@code true} if any form of automatic time zone detection is supported. */
+    public boolean isAutoDetectionFeatureSupported() {
+        return deviceHasTelephonyNetwork() || isGeoTimeZoneDetectionFeatureSupported();
+    }
+
+    private boolean deviceHasTelephonyNetwork() {
+        // TODO b/150583524 Avoid the use of a deprecated API.
+        return mContext.getSystemService(ConnectivityManager.class)
+                .isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+    }
+
+    /**
+     * Returns {@code true} if the location-based time zone detection feature can be supported on
+     * this device at all according to config. When {@code false}, implies that various other
+     * location-based settings will be turned off or rendered meaningless. Typically {@link
+     * #isGeoTimeZoneDetectionFeatureSupported()} should be used instead.
+     */
+    public boolean isGeoTimeZoneDetectionFeatureSupportedInConfig() {
+        return mGeoDetectionFeatureSupportedInConfig;
+    }
+
+    /**
+     * Returns {@code true} if the location-based time zone detection feature is supported on the
+     * device. This can be used during feature testing on builds that are capable of location time
+     * zone detection to enable / disable the feature for some users.
+     */
+    public boolean isGeoTimeZoneDetectionFeatureSupported() {
+        return mGeoDetectionFeatureSupportedInConfig
+                && isGeoTimeZoneDetectionFeatureSupportedInternal();
+    }
+
+    private boolean isGeoTimeZoneDetectionFeatureSupportedInternal() {
+        final boolean defaultEnabled = true;
+        return mServerFlags.getBoolean(
+                ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED,
+                defaultEnabled);
+    }
+
+    /**
+     * Returns {@code true} if the primary location time zone provider can be used.
+     */
+    public boolean isPrimaryLocationTimeZoneProviderEnabled() {
+        return getPrimaryLocationTimeZoneProviderEnabledOverride()
+                .orElse(isPrimaryLocationTimeZoneProviderEnabledInConfig());
+    }
+
+    private boolean isPrimaryLocationTimeZoneProviderEnabledInConfig() {
+        int providerEnabledConfigId = R.bool.config_enablePrimaryLocationTimeZoneProvider;
+        return getConfigBoolean(providerEnabledConfigId);
+    }
+
+    @NonNull
+    private Optional<Boolean> getPrimaryLocationTimeZoneProviderEnabledOverride() {
+        return mServerFlags.getOptionalBoolean(
+                ServerFlags.KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE);
+    }
+
+    /**
+     * Returns {@code true} if the secondary location time zone provider can be used.
+     */
+    public boolean isSecondaryLocationTimeZoneProviderEnabled() {
+        return getSecondaryLocationTimeZoneProviderEnabledOverride()
+                .orElse(isSecondaryLocationTimeZoneProviderEnabledInConfig());
+    }
+
+    private boolean isSecondaryLocationTimeZoneProviderEnabledInConfig() {
+        int providerEnabledConfigId = R.bool.config_enableSecondaryLocationTimeZoneProvider;
+        return getConfigBoolean(providerEnabledConfigId);
+    }
+
+    @NonNull
+    private Optional<Boolean> getSecondaryLocationTimeZoneProviderEnabledOverride() {
+        return mServerFlags.getOptionalBoolean(
+                ServerFlags.KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE);
+    }
+
+    /**
+     * Returns whether location time zone detection is enabled for users when there's no setting
+     * value. Intended for use during feature release testing to "opt-in" users that haven't shown
+     * an explicit preference.
+     */
+    public boolean isGeoDetectionEnabledForUsersByDefault() {
+        return mServerFlags.getBoolean(
+                ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT, false);
+    }
+
+    /**
+     * Returns whether location time zone detection is force enabled/disabled for users. Intended
+     * for use during feature release testing to force a given state.
+     */
+    @NonNull
+    public Optional<Boolean> getGeoDetectionSettingEnabledOverride() {
+        return mServerFlags.getOptionalBoolean(
+                ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE);
+    }
+
+    /**
+     * Returns the time to send to a location time zone provider that informs it how long it has
+     * to return its first time zone suggestion.
+     */
+    @NonNull
+    public Duration getLocationTimeZoneProviderInitializationTimeout() {
+        return mServerFlags.getDurationFromMillis(
+                ServerFlags.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS,
+                DEFAULT_PROVIDER_INITIALIZATION_TIMEOUT);
+    }
+
+    /**
+     * Returns the time added to {@link #getLocationTimeZoneProviderInitializationTimeout()} by the
+     * server before unilaterally declaring the provider is uncertain.
+     */
+    @NonNull
+    public Duration getLocationTimeZoneProviderInitializationTimeoutFuzz() {
+        return mServerFlags.getDurationFromMillis(
+                ServerFlags.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS,
+                DEFAULT_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ);
+    }
+
+    /**
+     * Returns the time after uncertainty is detected by providers before the location time zone
+     * manager makes a suggestion to the time zone detector.
+     */
+    @NonNull
+    public Duration getLocationTimeZoneUncertaintyDelay() {
+        return mServerFlags.getDurationFromMillis(
+                ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS,
+                DEFAULT_PROVIDER_UNCERTAINTY_DELAY);
+    }
+
+    private boolean getConfigBoolean(int providerEnabledConfigId) {
+        Resources resources = mContext.getResources();
+        return resources.getBoolean(providerEnabledConfigId);
+    }
+}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
index 203a8a4..cd220b1 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
@@ -27,16 +27,21 @@
  */
 public interface TimeZoneDetectorInternal extends Dumpable.Container {
 
-    /** Adds a listener that will be invoked when time zone detection configuration is changed. */
-    void addConfigurationListener(ConfigurationChangeListener listener);
+    /** Adds a listener that will be invoked when {@link ConfigurationInternal} may have changed. */
+    void addConfigurationListener(@NonNull ConfigurationChangeListener listener);
 
     /**
      * Removes a listener previously added via {@link
      * #addConfigurationListener(ConfigurationChangeListener)}.
      */
-    void removeConfigurationListener(ConfigurationChangeListener listener);
+    void removeConfigurationListener(@NonNull ConfigurationChangeListener listener);
 
-    /** Returns the {@link ConfigurationInternal} for the current user. */
+    /**
+     * Returns a snapshot of the {@link ConfigurationInternal} for the current user. This is only a
+     * snapshot so callers must use {@link #addConfigurationListener(ConfigurationChangeListener)}
+     * to be notified when it changes.
+     */
+    @NonNull
     ConfigurationInternal getCurrentUserConfigurationInternal();
 
     /**
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
index bd71ddf..c20400a 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -33,7 +33,6 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
-import android.os.SystemProperties;
 import android.util.ArrayMap;
 import android.util.IndentingPrintWriter;
 import android.util.Slog;
@@ -62,27 +61,6 @@
     static final String TAG = "time_zone_detector";
 
     /**
-     * A "feature switch" for location-based time zone detection. If this is {@code false}. It is
-     * initialized and never refreshed; it affects what services are started on boot so consistency
-     * is important.
-     */
-    @Nullable
-    private static Boolean sGeoLocationTimeZoneDetectionSupported;
-
-    /** Returns {@code true} if the location-based time zone detection feature is enabled. */
-    public static boolean isGeoLocationTimeZoneDetectionSupported(Context context) {
-        if (sGeoLocationTimeZoneDetectionSupported == null) {
-            // The config value is expected to be the main switch. Platform developers can also
-            // enable the feature using a persistent system property.
-            sGeoLocationTimeZoneDetectionSupported = context.getResources().getBoolean(
-                    com.android.internal.R.bool.config_enableGeolocationTimeZoneDetection)
-                    || SystemProperties.getBoolean(
-                            "persist.sys.location_time_zone_detection_feature_enabled", false);
-        }
-        return sGeoLocationTimeZoneDetectionSupported;
-    }
-
-    /**
      * Handles the service lifecycle for {@link TimeZoneDetectorService} and
      * {@link TimeZoneDetectorInternalImpl}.
      */
@@ -98,11 +76,10 @@
             Context context = getContext();
             Handler handler = FgThread.getHandler();
 
-            boolean geolocationTimeZoneDetectionSupported =
-                    isGeoLocationTimeZoneDetectionSupported(context);
+            ServiceConfigAccessor serviceConfigAccessor =
+                    ServiceConfigAccessor.getInstance(context);
             TimeZoneDetectorStrategy timeZoneDetectorStrategy =
-                    TimeZoneDetectorStrategyImpl.create(
-                            context, handler, geolocationTimeZoneDetectionSupported);
+                    TimeZoneDetectorStrategyImpl.create(context, handler, serviceConfigAccessor);
 
             // Create and publish the local service for use by internal callers.
             TimeZoneDetectorInternal internal =
@@ -330,7 +307,8 @@
     boolean isGeoTimeZoneDetectionSupported() {
         enforceManageTimeZoneDetectorPermission();
 
-        return isGeoLocationTimeZoneDetectionSupported(mContext);
+        return ServiceConfigAccessor.getInstance(mContext)
+                .isGeoTimeZoneDetectionFeatureSupported();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
index 0b1d6d7..8266f12 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
@@ -75,17 +75,21 @@
 public interface TimeZoneDetectorStrategy extends Dumpable, Dumpable.Container {
 
     /**
-     * Sets a listener that will be triggered whenever time zone detection configuration is
+     * Adds a listener that will be triggered whenever {@link ConfigurationInternal} may have
      * changed.
      */
     void addConfigChangeListener(@NonNull ConfigurationChangeListener listener);
 
-    /** Returns the user's time zone configuration. */
+    /**
+     * Returns a snapshot of the configuration that controls time zone detector behavior for the
+     * specified user.
+     */
     @NonNull
     ConfigurationInternal getConfigurationInternal(@UserIdInt int userId);
 
     /**
-     * Returns the configuration that controls time zone detector behavior for the current user.
+     * Returns a snapshot of the configuration that controls time zone detector behavior for the
+     * current user.
      */
     @NonNull
     ConfigurationInternal getCurrentUserConfigurationInternal();
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
index c464b74..d163a0e 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
@@ -38,7 +38,6 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.timedetector.DeviceConfig;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -204,11 +203,9 @@
      */
     public static TimeZoneDetectorStrategyImpl create(
             @NonNull Context context, @NonNull Handler handler,
-            boolean geoDetectionSupported) {
+            @NonNull ServiceConfigAccessor serviceConfigAccessor) {
 
-        DeviceConfig deviceConfig = new DeviceConfig();
-        EnvironmentImpl environment = new EnvironmentImpl(
-                context, handler, deviceConfig, geoDetectionSupported);
+        Environment environment = new EnvironmentImpl(context, handler, serviceConfigAccessor);
         return new TimeZoneDetectorStrategyImpl(environment);
     }
 
diff --git a/services/core/java/com/android/server/timezonedetector/location/ControllerEnvironmentImpl.java b/services/core/java/com/android/server/timezonedetector/location/ControllerEnvironmentImpl.java
index e463ee2..98e984d 100644
--- a/services/core/java/com/android/server/timezonedetector/location/ControllerEnvironmentImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/location/ControllerEnvironmentImpl.java
@@ -19,9 +19,9 @@
 import android.annotation.NonNull;
 
 import com.android.server.LocalServices;
-import com.android.server.timedetector.DeviceConfig;
 import com.android.server.timezonedetector.ConfigurationChangeListener;
 import com.android.server.timezonedetector.ConfigurationInternal;
+import com.android.server.timezonedetector.ServiceConfigAccessor;
 import com.android.server.timezonedetector.TimeZoneDetectorInternal;
 
 import java.time.Duration;
@@ -33,28 +33,19 @@
  */
 class ControllerEnvironmentImpl extends LocationTimeZoneProviderController.Environment {
 
-    // TODO(b/179488561): Put this back to 5 minutes when primary provider is fully implemented
-    private static final Duration DEFAULT_PROVIDER_INITIALIZATION_TIMEOUT = Duration.ofMinutes(1);
-    // TODO(b/179488561): Put this back to 5 minutes when primary provider is fully implemented
-    private static final Duration DEFAULT_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ =
-            Duration.ofSeconds(20);
-    private static final Duration DEFAULT_PROVIDER_UNCERTAINTY_DELAY = Duration.ofMinutes(5);
-
     @NonNull private final TimeZoneDetectorInternal mTimeZoneDetectorInternal;
-    @NonNull private final LocationTimeZoneProviderController mController;
-    @NonNull private final DeviceConfig mDeviceConfig;
+    @NonNull private final ServiceConfigAccessor mServiceConfigAccessor;
     @NonNull private final ConfigurationChangeListener mConfigurationChangeListener;
 
     ControllerEnvironmentImpl(@NonNull ThreadingDomain threadingDomain,
-            @NonNull DeviceConfig deviceConfig,
+            @NonNull ServiceConfigAccessor serviceConfigAccessor,
             @NonNull LocationTimeZoneProviderController controller) {
         super(threadingDomain);
-        mController = Objects.requireNonNull(controller);
-        mDeviceConfig = Objects.requireNonNull(deviceConfig);
+        mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor);
         mTimeZoneDetectorInternal = LocalServices.getService(TimeZoneDetectorInternal.class);
 
         // Listen for configuration changes.
-        mConfigurationChangeListener = () -> mThreadingDomain.post(mController::onConfigChanged);
+        mConfigurationChangeListener = () -> mThreadingDomain.post(controller::onConfigChanged);
         mTimeZoneDetectorInternal.addConfigurationListener(mConfigurationChangeListener);
     }
 
@@ -73,24 +64,18 @@
     @Override
     @NonNull
     Duration getProviderInitializationTimeout() {
-        return mDeviceConfig.getDurationFromMillis(
-                DeviceConfig.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS,
-                DEFAULT_PROVIDER_INITIALIZATION_TIMEOUT);
+        return mServiceConfigAccessor.getLocationTimeZoneProviderInitializationTimeout();
     }
 
     @Override
     @NonNull
     Duration getProviderInitializationTimeoutFuzz() {
-        return mDeviceConfig.getDurationFromMillis(
-                DeviceConfig.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS,
-                DEFAULT_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ);
+        return mServiceConfigAccessor.getLocationTimeZoneProviderInitializationTimeoutFuzz();
     }
 
     @Override
     @NonNull
     Duration getUncertaintyDelay() {
-        return mDeviceConfig.getDurationFromMillis(
-                DeviceConfig.KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS,
-                DEFAULT_PROVIDER_UNCERTAINTY_DELAY);
+        return mServiceConfigAccessor.getLocationTimeZoneUncertaintyDelay();
     }
 }
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
index 364eaf8..0d1692a 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
@@ -21,11 +21,11 @@
 import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_NONE;
 import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_SIMULATED;
 import static android.app.time.LocationTimeZoneManager.SECONDARY_PROVIDER_NAME;
+import static android.app.time.LocationTimeZoneManager.SERVICE_NAME;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
-import android.content.res.Resources;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
@@ -43,9 +43,8 @@
 import com.android.internal.util.Preconditions;
 import com.android.server.FgThread;
 import com.android.server.SystemService;
-import com.android.server.timedetector.DeviceConfig;
+import com.android.server.timezonedetector.ServiceConfigAccessor;
 import com.android.server.timezonedetector.TimeZoneDetectorInternal;
-import com.android.server.timezonedetector.TimeZoneDetectorService;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -96,28 +95,31 @@
 
         private LocationTimeZoneManagerService mService;
 
+        @NonNull
+        private final ServiceConfigAccessor mServerConfigAccessor;
+
         public Lifecycle(@NonNull Context context) {
             super(Objects.requireNonNull(context));
+            mServerConfigAccessor = ServiceConfigAccessor.getInstance(context);
         }
 
         @Override
         public void onStart() {
             Context context = getContext();
-            if (TimeZoneDetectorService.isGeoLocationTimeZoneDetectionSupported(context)) {
+            if (mServerConfigAccessor.isGeoTimeZoneDetectionFeatureSupportedInConfig()) {
                 mService = new LocationTimeZoneManagerService(context);
 
                 // The service currently exposes no LocalService or Binder API, but it extends
                 // Binder and is registered as a binder service so it can receive shell commands.
-                publishBinderService("location_time_zone_manager", mService);
+                publishBinderService(SERVICE_NAME, mService);
             } else {
-                Slog.i(TAG, getClass() + " is disabled");
+                Slog.d(TAG, "Geo time zone detection feature is disabled in config");
             }
         }
 
         @Override
-        public void onBootPhase(int phase) {
-            Context context = getContext();
-            if (TimeZoneDetectorService.isGeoLocationTimeZoneDetectionSupported(context)) {
+        public void onBootPhase(@BootPhase int phase) {
+            if (mServerConfigAccessor.isGeoTimeZoneDetectionFeatureSupportedInConfig()) {
                 if (phase == PHASE_SYSTEM_SERVICES_READY) {
                     // The location service must be functioning after this boot phase.
                     mService.onSystemReady();
@@ -159,6 +161,9 @@
     /** The shared lock from {@link #mThreadingDomain}. */
     @NonNull private final Object mSharedLock;
 
+    @NonNull
+    private final ServiceConfigAccessor mServiceConfigAccessor;
+
     // Lazily initialized. Can be null if the service has been stopped.
     @GuardedBy("mSharedLock")
     private ControllerImpl mLocationTimeZoneDetectorController;
@@ -180,24 +185,38 @@
         mHandler = FgThread.getHandler();
         mThreadingDomain = new HandlerThreadingDomain(mHandler);
         mSharedLock = mThreadingDomain.getLockObject();
+        mServiceConfigAccessor = ServiceConfigAccessor.getInstance(mContext);
     }
 
+    // According to the SystemService docs: All lifecycle methods are called from the system
+    // server's main looper thread.
     void onSystemReady() {
-        // Called on an arbitrary thread during initialization.
-        synchronized (mSharedLock) {
-            // TODO(b/152744911): LocationManagerService watches for packages disappearing. Need to
-            //  do anything here?
+        mServiceConfigAccessor.addListener(this::handleServiceConfigurationChangedOnMainThread);
+    }
 
-            // TODO(b/152744911): LocationManagerService watches for foreground app changes. Need to
-            //  do anything here?
-            // TODO(b/152744911): LocationManagerService watches screen state. Need to do anything
-            //  here?
+    private void handleServiceConfigurationChangedOnMainThread() {
+        // This method is called on the main thread, but service logic takes place on the threading
+        // domain thread, so we post the work there.
+
+        // The way all service-level configuration changes are handled is to just restart this
+        // service - this is simple and effective, and service configuration changes should be rare.
+        mThreadingDomain.post(this::restartIfRequiredOnDomainThread);
+    }
+
+    private void restartIfRequiredOnDomainThread() {
+        mThreadingDomain.assertCurrentThread();
+
+        synchronized (mSharedLock) {
+            // Stop and start the service, waiting until completion.
+            stopOnDomainThread();
+            startOnDomainThread();
         }
     }
 
+    // According to the SystemService docs: All lifecycle methods are called from the system
+    // server's main looper thread.
     void onSystemThirdPartyAppsCanStart() {
-        // Called on an arbitrary thread during initialization. We do not want to wait for
-        // completion as it would delay boot.
+        // Do not wait for completion as it would delay boot.
         final boolean waitForCompletion = false;
         startInternal(waitForCompletion);
     }
@@ -205,6 +224,9 @@
     /**
      * Starts the service during server initialization or during tests after a call to
      * {@link #stop()}.
+     *
+     * <p>Because this method posts work to the {@code mThreadingDomain} thread and waits for
+     * completion, it cannot be called from the {@code mThreadingDomain} thread.
      */
     void start() {
         enforceManageTimeZoneDetectorPermission();
@@ -214,28 +236,17 @@
     }
 
     /**
-     * Starts the service during server initialization or during tests after a call to
-     * {@link #stop()}.
+     * Starts the service during server initialization, if the configuration changes or during tests
+     * after a call to {@link #stop()}.
      *
      * <p>To avoid tests needing to sleep, when {@code waitForCompletion} is {@code true}, this
      * method will not return until all the system server components have started.
+     *
+     * <p>Because this method posts work to the {@code mThreadingDomain} thread, it cannot be
+     * called from the {@code mThreadingDomain} thread when {@code waitForCompletion} is true.
      */
     private void startInternal(boolean waitForCompletion) {
-        Runnable runnable = () -> {
-            synchronized (mSharedLock) {
-                if (mLocationTimeZoneDetectorController == null) {
-                    LocationTimeZoneProvider primary = createPrimaryProvider();
-                    LocationTimeZoneProvider secondary = createSecondaryProvider();
-                    mLocationTimeZoneDetectorController =
-                            new ControllerImpl(mThreadingDomain, primary, secondary);
-                    DeviceConfig deviceConfig = new DeviceConfig();
-                    mEnvironment = new ControllerEnvironmentImpl(
-                            mThreadingDomain, deviceConfig, mLocationTimeZoneDetectorController);
-                    ControllerCallbackImpl callback = new ControllerCallbackImpl(mThreadingDomain);
-                    mLocationTimeZoneDetectorController.initialize(mEnvironment, callback);
-                }
-            }
-        };
+        Runnable runnable = this::startOnDomainThread;
         if (waitForCompletion) {
             mThreadingDomain.postAndWait(runnable, BLOCKING_OP_WAIT_DURATION_MILLIS);
         } else {
@@ -243,11 +254,38 @@
         }
     }
 
+    private void startOnDomainThread() {
+        mThreadingDomain.assertCurrentThread();
+
+        synchronized (mSharedLock) {
+            if (!mServiceConfigAccessor.isGeoTimeZoneDetectionFeatureSupported()) {
+                debugLog("Not starting " + SERVICE_NAME + ": it is disabled in service config");
+                return;
+            }
+
+            if (mLocationTimeZoneDetectorController == null) {
+                LocationTimeZoneProvider primary = createPrimaryProvider();
+                LocationTimeZoneProvider secondary = createSecondaryProvider();
+
+                ControllerImpl controller =
+                        new ControllerImpl(mThreadingDomain, primary, secondary);
+                ControllerEnvironmentImpl environment = new ControllerEnvironmentImpl(
+                        mThreadingDomain, mServiceConfigAccessor, controller);
+                ControllerCallbackImpl callback = new ControllerCallbackImpl(mThreadingDomain);
+                controller.initialize(environment, callback);
+
+                mEnvironment = environment;
+                mLocationTimeZoneDetectorController = controller;
+            }
+        }
+    }
+
+    @NonNull
     private LocationTimeZoneProvider createPrimaryProvider() {
         LocationTimeZoneProviderProxy proxy;
         if (isProviderInSimulationMode(PRIMARY_PROVIDER_NAME)) {
             proxy = new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
-        } else if (isProviderDisabled(PRIMARY_PROVIDER_NAME)) {
+        } else if (!isProviderEnabled(PRIMARY_PROVIDER_NAME)) {
             proxy = new NullLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
         } else {
             proxy = new RealLocationTimeZoneProviderProxy(
@@ -262,11 +300,12 @@
         return new BinderLocationTimeZoneProvider(mThreadingDomain, PRIMARY_PROVIDER_NAME, proxy);
     }
 
+    @NonNull
     private LocationTimeZoneProvider createSecondaryProvider() {
         LocationTimeZoneProviderProxy proxy;
         if (isProviderInSimulationMode(SECONDARY_PROVIDER_NAME)) {
             proxy = new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
-        } else if (isProviderDisabled(SECONDARY_PROVIDER_NAME)) {
+        } else if (!isProviderEnabled(SECONDARY_PROVIDER_NAME)) {
             proxy = new NullLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
         } else {
             proxy = new RealLocationTimeZoneProviderProxy(
@@ -282,33 +321,27 @@
     }
 
     /** Used for bug triage and in tests to simulate provider events. */
-    private boolean isProviderInSimulationMode(String providerName) {
+    private boolean isProviderInSimulationMode(@NonNull String providerName) {
         return isProviderModeOverrideSet(providerName, PROVIDER_MODE_OVERRIDE_SIMULATED);
     }
 
-    /** Used for bug triage, tests and experiments to remove a provider. */
-    private boolean isProviderDisabled(String providerName) {
-        return !isProviderEnabledInConfig(providerName)
-                || isProviderModeOverrideSet(providerName, PROVIDER_MODE_OVERRIDE_DISABLED);
-    }
+    /** Used for bug triage, and by tests and experiments to remove a provider. */
+    private boolean isProviderEnabled(@NonNull String providerName) {
+        if (isProviderModeOverrideSet(providerName, PROVIDER_MODE_OVERRIDE_DISABLED)) {
+            return false;
+        }
 
-    private boolean isProviderEnabledInConfig(String providerName) {
-        int providerEnabledConfigId;
         switch (providerName) {
             case PRIMARY_PROVIDER_NAME: {
-                providerEnabledConfigId = R.bool.config_enablePrimaryLocationTimeZoneProvider;
-                break;
+                return mServiceConfigAccessor.isPrimaryLocationTimeZoneProviderEnabled();
             }
             case SECONDARY_PROVIDER_NAME: {
-                providerEnabledConfigId = R.bool.config_enableSecondaryLocationTimeZoneProvider;
-                break;
+                return mServiceConfigAccessor.isSecondaryLocationTimeZoneProviderEnabled();
             }
             default: {
                 throw new IllegalArgumentException(providerName);
             }
         }
-        Resources resources = mContext.getResources();
-        return resources.getBoolean(providerEnabledConfigId);
     }
 
     private boolean isProviderModeOverrideSet(@NonNull String providerName, @NonNull String mode) {
@@ -326,22 +359,29 @@
     }
 
     /**
-     * Stops the service for tests. To avoid tests needing to sleep, this method will not return
-     * until all the system server components have stopped.
+     * Stops the service for tests and other rare cases. To avoid tests needing to sleep, this
+     * method will not return until all the system server components have stopped.
+     *
+     * <p>Because this method posts work to the {@code mThreadingDomain} thread and waits it cannot
+     * be called from the {@code mThreadingDomain} thread.
      */
     void stop() {
         enforceManageTimeZoneDetectorPermission();
 
-        mThreadingDomain.postAndWait(() -> {
-            synchronized (mSharedLock) {
-                if (mLocationTimeZoneDetectorController != null) {
-                    mLocationTimeZoneDetectorController.destroy();
-                    mLocationTimeZoneDetectorController = null;
-                    mEnvironment.destroy();
-                    mEnvironment = null;
-                }
+        mThreadingDomain.postAndWait(this::stopOnDomainThread, BLOCKING_OP_WAIT_DURATION_MILLIS);
+    }
+
+    private void stopOnDomainThread() {
+        mThreadingDomain.assertCurrentThread();
+
+        synchronized (mSharedLock) {
+            if (mLocationTimeZoneDetectorController != null) {
+                mLocationTimeZoneDetectorController.destroy();
+                mLocationTimeZoneDetectorController = null;
+                mEnvironment.destroy();
+                mEnvironment = null;
             }
-        }, BLOCKING_OP_WAIT_DURATION_MILLIS);
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java
index b53150c..bdf4a70 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java
@@ -21,6 +21,7 @@
 import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_NONE;
 import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_SIMULATED;
 import static android.app.time.LocationTimeZoneManager.SECONDARY_PROVIDER_NAME;
+import static android.app.time.LocationTimeZoneManager.SERVICE_NAME;
 import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_DUMP_STATE;
 import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_RECORD_PROVIDER_STATES;
 import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND;
@@ -102,7 +103,7 @@
     @Override
     public void onHelp() {
         final PrintWriter pw = getOutPrintWriter();
-        pw.println("Location Time Zone Manager (location_time_zone_manager) commands for tests:");
+        pw.printf("Location Time Zone Manager (%s) commands for tests:\n", SERVICE_NAME);
         pw.println("  help");
         pw.println("    Print this help text.");
         pw.printf("  %s\n", SHELL_COMMAND_START);
diff --git a/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java b/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java
index 38211ef..0b51488 100644
--- a/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java
+++ b/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java
@@ -25,7 +25,6 @@
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
@@ -40,7 +39,8 @@
 import android.util.IndentingPrintWriter;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.server.ServiceWatcher;
+import com.android.server.servicewatcher.ServiceWatcher;
+import com.android.server.servicewatcher.ServiceWatcher.BoundService;
 
 import java.util.Objects;
 import java.util.function.Predicate;
@@ -123,7 +123,7 @@
         return resolves;
     }
 
-    private void onBind(IBinder binder, ComponentName componentName) {
+    private void onBind(IBinder binder, BoundService boundService) {
         mThreadingDomain.assertCurrentThread();
 
         synchronized (mSharedLock) {
diff --git a/services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderRequest.java b/services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderRequest.java
index 1482031..e8386bc 100644
--- a/services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderRequest.java
+++ b/services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderRequest.java
@@ -63,8 +63,6 @@
         return mSendUpdates;
     }
 
-    // TODO(b/152744911) - once there are a couple of implementations, decide whether this needs to
-    //  be passed to the TimeZoneProviderService and remove if it is not useful.
     /**
      * Returns the maximum time that the provider is allowed to initialize before it is expected to
      * send an event of any sort. Only valid when {@link #sendUpdates()} is {@code true}. Failure to
diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
index b6ddd93..b2db9f5 100644
--- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
+++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
@@ -65,7 +65,7 @@
     @NonNull private final NetworkCallback mRouteSelectionCallback = new RouteSelectionCallback();
 
     @NonNull private TelephonySubscriptionSnapshot mLastSnapshot;
-    private boolean mIsRunning = true;
+    private boolean mIsQuitting = false;
 
     @Nullable private UnderlyingNetworkRecord mCurrentRecord;
     @Nullable private UnderlyingNetworkRecord.Builder mRecordInProgress;
@@ -151,7 +151,7 @@
         mVcnContext.ensureRunningOnLooperThread();
 
         // Don't bother re-filing NetworkRequests if this Tracker has been torn down.
-        if (!mIsRunning) {
+        if (mIsQuitting) {
             return;
         }
 
@@ -205,7 +205,7 @@
         }
         mCellBringupCallbacks.clear();
 
-        mIsRunning = false;
+        mIsQuitting = true;
     }
 
     /** Returns whether the currently selected Network matches the given network. */
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index 6ad30b5..9d39c67 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -16,6 +16,8 @@
 
 package com.android.server.vcn;
 
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
+
 import static com.android.server.VcnManagementService.VDBG;
 
 import android.annotation.NonNull;
@@ -84,6 +86,13 @@
      */
     private static final int MSG_EVENT_SUBSCRIPTIONS_CHANGED = MSG_EVENT_BASE + 2;
 
+    /**
+     * A GatewayConnection owned by this VCN quit.
+     *
+     * @param obj VcnGatewayConnectionConfig
+     */
+    private static final int MSG_EVENT_GATEWAY_CONNECTION_QUIT = MSG_EVENT_BASE + 3;
+
     /** Triggers an immediate teardown of the entire Vcn, including GatewayConnections. */
     private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE;
 
@@ -208,6 +217,9 @@
             case MSG_EVENT_SUBSCRIPTIONS_CHANGED:
                 handleSubscriptionsChanged((TelephonySubscriptionSnapshot) msg.obj);
                 break;
+            case MSG_EVENT_GATEWAY_CONNECTION_QUIT:
+                handleGatewayConnectionQuit((VcnGatewayConnectionConfig) msg.obj);
+                break;
             case MSG_CMD_TEARDOWN:
                 handleTeardown();
                 break;
@@ -263,7 +275,7 @@
 
         // If preexisting VcnGatewayConnection(s) satisfy request, return
         for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) {
-            if (requestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
+            if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
                 if (VDBG) {
                     Slog.v(
                             getLogTag(),
@@ -278,7 +290,7 @@
         // up
         for (VcnGatewayConnectionConfig gatewayConnectionConfig :
                 mConfig.getGatewayConnectionConfigs()) {
-            if (requestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
+            if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
                 Slog.v(
                         getLogTag(),
                         "Bringing up new VcnGatewayConnection for request " + request.requestId);
@@ -289,12 +301,21 @@
                                 mSubscriptionGroup,
                                 mLastSnapshot,
                                 gatewayConnectionConfig,
-                                new VcnGatewayStatusCallbackImpl());
+                                new VcnGatewayStatusCallbackImpl(gatewayConnectionConfig));
                 mVcnGatewayConnections.put(gatewayConnectionConfig, vcnGatewayConnection);
             }
         }
     }
 
+    private void handleGatewayConnectionQuit(VcnGatewayConnectionConfig config) {
+        Slog.v(getLogTag(), "VcnGatewayConnection quit: " + config);
+        mVcnGatewayConnections.remove(config);
+
+        // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be satisfied
+        // start a new GatewayConnection)
+        mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
+    }
+
     private void handleSubscriptionsChanged(@NonNull TelephonySubscriptionSnapshot snapshot) {
         mLastSnapshot = snapshot;
 
@@ -305,9 +326,10 @@
         }
     }
 
-    private boolean requestSatisfiedByGatewayConnectionConfig(
+    private boolean isRequestSatisfiedByGatewayConnectionConfig(
             @NonNull NetworkRequest request, @NonNull VcnGatewayConnectionConfig config) {
         final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
+        builder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
         for (int cap : config.getAllExposedCapabilities()) {
             builder.addCapability(cap);
         }
@@ -339,9 +361,23 @@
                 @VcnErrorCode int errorCode,
                 @Nullable String exceptionClass,
                 @Nullable String exceptionMessage);
+
+        /** Called by a VcnGatewayConnection to indicate that it has fully torn down. */
+        void onQuit();
     }
 
     private class VcnGatewayStatusCallbackImpl implements VcnGatewayStatusCallback {
+        public final VcnGatewayConnectionConfig mGatewayConnectionConfig;
+
+        VcnGatewayStatusCallbackImpl(VcnGatewayConnectionConfig gatewayConnectionConfig) {
+            mGatewayConnectionConfig = gatewayConnectionConfig;
+        }
+
+        @Override
+        public void onQuit() {
+            sendMessage(obtainMessage(MSG_EVENT_GATEWAY_CONNECTION_QUIT, mGatewayConnectionConfig));
+        }
+
         @Override
         public void onEnteredSafeMode() {
             sendMessage(obtainMessage(MSG_CMD_ENTER_SAFE_MODE));
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 06748a3..6bc9978 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -168,6 +168,8 @@
     private static final String DISCONNECT_REASON_INTERNAL_ERROR = "Uncaught exception: ";
     private static final String DISCONNECT_REASON_UNDERLYING_NETWORK_LOST =
             "Underlying Network lost";
+    private static final String DISCONNECT_REASON_NETWORK_AGENT_UNWANTED =
+            "NetworkAgent was unwanted";
     private static final String DISCONNECT_REASON_TEARDOWN = "teardown() called on VcnTunnel";
     private static final int TOKEN_ALL = Integer.MIN_VALUE;
 
@@ -379,13 +381,16 @@
         /** The reason why the disconnect was requested. */
         @NonNull public final String reason;
 
-        EventDisconnectRequestedInfo(@NonNull String reason) {
+        public final boolean shouldQuit;
+
+        EventDisconnectRequestedInfo(@NonNull String reason, boolean shouldQuit) {
             this.reason = Objects.requireNonNull(reason);
+            this.shouldQuit = shouldQuit;
         }
 
         @Override
         public int hashCode() {
-            return Objects.hash(reason);
+            return Objects.hash(reason, shouldQuit);
         }
 
         @Override
@@ -395,7 +400,7 @@
             }
 
             final EventDisconnectRequestedInfo rhs = (EventDisconnectRequestedInfo) other;
-            return reason.equals(rhs.reason);
+            return reason.equals(rhs.reason) && shouldQuit == rhs.shouldQuit;
         }
     }
 
@@ -488,8 +493,14 @@
      */
     @NonNull private final VcnWakeLock mWakeLock;
 
-    /** Running state of this VcnGatewayConnection. */
-    private boolean mIsRunning = true;
+    /**
+     * Whether the VcnGatewayConnection is in the process of irreversibly quitting.
+     *
+     * <p>This variable is false for the lifecycle of the VcnGatewayConnection, until a command to
+     * teardown has been received. This may be flipped due to events such as the Network becoming
+     * unwanted, the owning VCN entering safe mode, or an irrecoverable internal failure.
+     */
+    private boolean mIsQuitting = false;
 
     /**
      * The token used by the primary/current/active session.
@@ -622,10 +633,8 @@
      * <p>Once torn down, this VcnTunnel CANNOT be started again.
      */
     public void teardownAsynchronously() {
-        sendMessageAndAcquireWakeLock(
-                EVENT_DISCONNECT_REQUESTED,
-                TOKEN_ALL,
-                new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN));
+        sendDisconnectRequestedAndAcquireWakelock(
+                DISCONNECT_REASON_TEARDOWN, true /* shouldQuit */);
 
         // TODO: Notify VcnInstance (via callbacks) of permanent teardown of this tunnel, since this
         // is also called asynchronously when a NetworkAgent becomes unwanted
@@ -646,6 +655,8 @@
         cancelSafeModeAlarm();
 
         mUnderlyingNetworkTracker.teardown();
+
+        mGatewayStatusCallback.onQuit();
     }
 
     /**
@@ -693,7 +704,7 @@
     private void acquireWakeLock() {
         mVcnContext.ensureRunningOnLooperThread();
 
-        if (mIsRunning) {
+        if (!mIsQuitting) {
             mWakeLock.acquire();
         }
     }
@@ -892,7 +903,7 @@
                         TOKEN_ALL,
                         0 /* arg2 */,
                         new EventDisconnectRequestedInfo(
-                                DISCONNECT_REASON_UNDERLYING_NETWORK_LOST));
+                                DISCONNECT_REASON_UNDERLYING_NETWORK_LOST, false /* shouldQuit */));
         mDisconnectRequestAlarm =
                 createScheduledAlarm(
                         DISCONNECT_REQUEST_ALARM,
@@ -909,7 +920,8 @@
         // Cancel any existing disconnect due to previous loss of underlying network
         removeEqualMessages(
                 EVENT_DISCONNECT_REQUESTED,
-                new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST));
+                new EventDisconnectRequestedInfo(
+                        DISCONNECT_REASON_UNDERLYING_NETWORK_LOST, false /* shouldQuit */));
     }
 
     private void setRetryTimeoutAlarm(long delay) {
@@ -1041,11 +1053,8 @@
                 enterState();
             } catch (Exception e) {
                 Slog.wtf(TAG, "Uncaught exception", e);
-                sendMessageAndAcquireWakeLock(
-                        EVENT_DISCONNECT_REQUESTED,
-                        TOKEN_ALL,
-                        new EventDisconnectRequestedInfo(
-                                DISCONNECT_REASON_INTERNAL_ERROR + e.toString()));
+                sendDisconnectRequestedAndAcquireWakelock(
+                        DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */);
             }
         }
 
@@ -1083,11 +1092,8 @@
                 processStateMsg(msg);
             } catch (Exception e) {
                 Slog.wtf(TAG, "Uncaught exception", e);
-                sendMessageAndAcquireWakeLock(
-                        EVENT_DISCONNECT_REQUESTED,
-                        TOKEN_ALL,
-                        new EventDisconnectRequestedInfo(
-                                DISCONNECT_REASON_INTERNAL_ERROR + e.toString()));
+                sendDisconnectRequestedAndAcquireWakelock(
+                        DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */);
             }
 
             // Attempt to release the WakeLock - only possible if the Handler queue is empty
@@ -1104,11 +1110,8 @@
                 exitState();
             } catch (Exception e) {
                 Slog.wtf(TAG, "Uncaught exception", e);
-                sendMessageAndAcquireWakeLock(
-                        EVENT_DISCONNECT_REQUESTED,
-                        TOKEN_ALL,
-                        new EventDisconnectRequestedInfo(
-                                DISCONNECT_REASON_INTERNAL_ERROR + e.toString()));
+                sendDisconnectRequestedAndAcquireWakelock(
+                        DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */);
             }
         }
 
@@ -1141,11 +1144,11 @@
             }
         }
 
-        protected void handleDisconnectRequested(String msg) {
+        protected void handleDisconnectRequested(EventDisconnectRequestedInfo info) {
             // TODO(b/180526152): notify VcnStatusCallback for Network loss
 
-            Slog.v(TAG, "Tearing down. Cause: " + msg);
-            mIsRunning = false;
+            Slog.v(TAG, "Tearing down. Cause: " + info.reason);
+            mIsQuitting = info.shouldQuit;
 
             teardownNetwork();
 
@@ -1177,7 +1180,7 @@
     private class DisconnectedState extends BaseState {
         @Override
         protected void enterState() {
-            if (!mIsRunning) {
+            if (mIsQuitting) {
                 quitNow(); // Ignore all queued events; cleanup is complete.
             }
 
@@ -1200,9 +1203,11 @@
                     }
                     break;
                 case EVENT_DISCONNECT_REQUESTED:
-                    mIsRunning = false;
+                    if (((EventDisconnectRequestedInfo) msg.obj).shouldQuit) {
+                        mIsQuitting = true;
 
-                    quitNow();
+                        quitNow();
+                    }
                     break;
                 default:
                     logUnhandledMessage(msg);
@@ -1284,10 +1289,11 @@
 
                     break;
                 case EVENT_DISCONNECT_REQUESTED:
+                    EventDisconnectRequestedInfo info = ((EventDisconnectRequestedInfo) msg.obj);
+                    mIsQuitting = info.shouldQuit;
                     teardownNetwork();
 
-                    String reason = ((EventDisconnectRequestedInfo) msg.obj).reason;
-                    if (reason.equals(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)) {
+                    if (info.reason.equals(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)) {
                         // TODO(b/180526152): notify VcnStatusCallback for Network loss
 
                         // Will trigger EVENT_SESSION_CLOSED immediately.
@@ -1300,7 +1306,7 @@
                 case EVENT_SESSION_CLOSED:
                     mIkeSession = null;
 
-                    if (mIsRunning && mUnderlying != null) {
+                    if (!mIsQuitting && mUnderlying != null) {
                         transitionTo(mSkipRetryTimeout ? mConnectingState : mRetryTimeoutState);
                     } else {
                         teardownNetwork();
@@ -1391,7 +1397,7 @@
                     transitionTo(mConnectedState);
                     break;
                 case EVENT_DISCONNECT_REQUESTED:
-                    handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
+                    handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
                     break;
                 case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
                     mGatewayStatusCallback.onEnteredSafeMode();
@@ -1438,6 +1444,7 @@
                             mVcnContext.getVcnNetworkProvider()) {
                         @Override
                         public void unwanted() {
+                            Slog.d(TAG, "NetworkAgent was unwanted");
                             teardownAsynchronously();
                         }
 
@@ -1471,7 +1478,7 @@
                 @NonNull IpSecTransform transform,
                 int direction) {
             try {
-                // TODO(b/180163196): Set underlying network of tunnel interface
+                tunnelIface.setUnderlyingNetwork(underlyingNetwork);
 
                 // Transforms do not need to be persisted; the IkeSession will keep them alive
                 mIpSecManager.applyTunnelModeTransform(tunnelIface, direction, transform);
@@ -1577,7 +1584,7 @@
                     setupInterfaceAndNetworkAgent(mCurrentToken, mTunnelIface, mChildConfig);
                     break;
                 case EVENT_DISCONNECT_REQUESTED:
-                    handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
+                    handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
                     break;
                 case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
                     mGatewayStatusCallback.onEnteredSafeMode();
@@ -1682,7 +1689,7 @@
                     transitionTo(mConnectingState);
                     break;
                 case EVENT_DISCONNECT_REQUESTED:
-                    handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
+                    handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
                     break;
                 case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
                     mGatewayStatusCallback.onEnteredSafeMode();
@@ -1905,13 +1912,13 @@
     }
 
     @VisibleForTesting(visibility = Visibility.PRIVATE)
-    boolean isRunning() {
-        return mIsRunning;
+    boolean isQuitting() {
+        return mIsQuitting;
     }
 
     @VisibleForTesting(visibility = Visibility.PRIVATE)
-    void setIsRunning(boolean isRunning) {
-        mIsRunning = isRunning;
+    void setIsQuitting(boolean isQuitting) {
+        mIsQuitting = isQuitting;
     }
 
     @VisibleForTesting(visibility = Visibility.PRIVATE)
@@ -1924,6 +1931,14 @@
         mIkeSession = session;
     }
 
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    void sendDisconnectRequestedAndAcquireWakelock(String reason, boolean shouldQuit) {
+        sendMessageAndAcquireWakeLock(
+                EVENT_DISCONNECT_REQUESTED,
+                TOKEN_ALL,
+                new EventDisconnectRequestedInfo(reason, shouldQuit));
+    }
+
     private IkeSessionParams buildIkeParams() {
         // TODO: Implement this once IkeSessionParams is persisted
         return null;
diff --git a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
index bfeec01..a909695 100644
--- a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
+++ b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
@@ -67,9 +67,7 @@
         mListeners.add(listener);
 
         // Send listener all cached requests
-        for (NetworkRequestEntry entry : mRequests.values()) {
-            notifyListenerForEvent(listener, entry);
-        }
+        resendAllRequests(listener);
     }
 
     /** Unregisters the specified listener from receiving future NetworkRequests. */
@@ -78,6 +76,14 @@
         mListeners.remove(listener);
     }
 
+    /** Sends all cached NetworkRequest(s) to the specified listener. */
+    @VisibleForTesting(visibility = Visibility.PACKAGE)
+    public void resendAllRequests(@NonNull NetworkRequestListener listener) {
+        for (NetworkRequestEntry entry : mRequests.values()) {
+            notifyListenerForEvent(listener, entry);
+        }
+    }
+
     private void notifyListenerForEvent(
             @NonNull NetworkRequestListener listener, @NonNull NetworkRequestEntry entry) {
         listener.onNetworkRequested(entry.mRequest, entry.mScore, entry.mProviderId);
diff --git a/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java b/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java
index 685dce4..96f84dc 100644
--- a/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java
+++ b/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java
@@ -16,6 +16,7 @@
 
 package com.android.server.vibrator;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.hardware.input.InputManager;
 import android.os.CombinedVibrationEffect;
@@ -33,7 +34,11 @@
 
     private final Object mLock = new Object();
     private final Handler mHandler;
-    private final InputManager mInputManager;
+    private final Context mContext;
+
+    @GuardedBy("mLock")
+    @Nullable
+    private InputManager mInputManager;
 
     @GuardedBy("mLock")
     private final SparseArray<VibratorManager> mInputDeviceVibrators = new SparseArray<>();
@@ -47,7 +52,13 @@
 
     InputDeviceDelegate(Context context, Handler handler) {
         mHandler = handler;
-        mInputManager = context.getSystemService(InputManager.class);
+        mContext = context;
+    }
+
+    public void onSystemReady() {
+        synchronized (mLock) {
+            mInputManager = mContext.getSystemService(InputManager.class);
+        }
     }
 
     @Override
@@ -116,6 +127,10 @@
      */
     public boolean updateInputDeviceVibrators(boolean vibrateInputDevices) {
         synchronized (mLock) {
+            if (mInputManager == null) {
+                // Ignore update, service not loaded yet so change cannot be applied.
+                return false;
+            }
             if (vibrateInputDevices == mShouldVibrateInputDevices) {
                 // No need to update if settings haven't changed.
                 return false;
@@ -150,6 +165,10 @@
 
     private void updateInputDevice(int deviceId) {
         synchronized (mLock) {
+            if (mInputManager == null) {
+                // Ignore update, service not loaded yet so change cannot be applied.
+                return;
+            }
             if (!mShouldVibrateInputDevices) {
                 // No need to keep this device vibrator if setting is off.
                 return;
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index 334129d..4a07c1a 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -16,6 +16,7 @@
 
 package com.android.server.vibrator;
 
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.IUidObserver;
 import android.content.Context;
@@ -57,8 +58,6 @@
 
     private final Object mLock = new Object();
     private final Context mContext;
-    private final Vibrator mVibrator;
-    private final AudioManager mAudioManager;
     private final SettingsObserver mSettingObserver;
     @VisibleForTesting
     final UidObserver mUidObserver;
@@ -68,6 +67,13 @@
     private final SparseArray<VibrationEffect> mFallbackEffects;
 
     @GuardedBy("mLock")
+    @Nullable
+    private Vibrator mVibrator;
+    @GuardedBy("mLock")
+    @Nullable
+    private AudioManager mAudioManager;
+
+    @GuardedBy("mLock")
     private boolean mVibrateInputDevices;
     @GuardedBy("mLock")
     private boolean mVibrateWhenRinging;
@@ -86,22 +92,9 @@
 
     VibrationSettings(Context context, Handler handler) {
         mContext = context;
-        mVibrator = context.getSystemService(Vibrator.class);
-        mAudioManager = context.getSystemService(AudioManager.class);
         mSettingObserver = new SettingsObserver(handler);
         mUidObserver = new UidObserver();
 
-        registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES));
-        registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_WHEN_RINGING));
-        registerSettingsObserver(Settings.Global.getUriFor(Settings.Global.APPLY_RAMPING_RINGER));
-        registerSettingsObserver(Settings.Global.getUriFor(Settings.Global.ZEN_MODE));
-        registerSettingsObserver(
-                Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY));
-        registerSettingsObserver(
-                Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY));
-        registerSettingsObserver(
-                Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY));
-
         VibrationEffect clickEffect = createEffectFromResource(
                 com.android.internal.R.array.config_virtualKeyVibePattern);
         VibrationEffect doubleClickEffect = VibrationEffect.createWaveform(
@@ -119,6 +112,15 @@
         mFallbackEffects.put(VibrationEffect.EFFECT_TEXTURE_TICK,
                 VibrationEffect.get(VibrationEffect.EFFECT_TICK, false));
 
+        // Update with current values from settings.
+        updateSettings();
+    }
+
+    public void onSystemReady() {
+        synchronized (mLock) {
+            mVibrator = mContext.getSystemService(Vibrator.class);
+            mAudioManager = mContext.getSystemService(AudioManager.class);
+        }
         try {
             ActivityManager.getService().registerUidObserver(mUidObserver,
                     ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE,
@@ -148,7 +150,18 @@
                     }
                 });
 
-        // Update with current values from settings.
+        registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES));
+        registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_WHEN_RINGING));
+        registerSettingsObserver(Settings.Global.getUriFor(Settings.Global.APPLY_RAMPING_RINGER));
+        registerSettingsObserver(Settings.Global.getUriFor(Settings.Global.ZEN_MODE));
+        registerSettingsObserver(
+                Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY));
+        registerSettingsObserver(
+                Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY));
+        registerSettingsObserver(
+                Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY));
+
+        // Update with newly loaded services.
         updateSettings();
     }
 
@@ -178,17 +191,21 @@
      * @return The vibration intensity, one of Vibrator.VIBRATION_INTENSITY_*
      */
     public int getDefaultIntensity(int usageHint) {
-        if (isRingtone(usageHint)) {
-            return mVibrator.getDefaultRingVibrationIntensity();
-        } else if (isNotification(usageHint)) {
-            return mVibrator.getDefaultNotificationVibrationIntensity();
-        } else if (isHapticFeedback(usageHint)) {
-            return mVibrator.getDefaultHapticFeedbackIntensity();
-        } else if (isAlarm(usageHint)) {
+        if (isAlarm(usageHint)) {
             return Vibrator.VIBRATION_INTENSITY_HIGH;
-        } else {
-            return Vibrator.VIBRATION_INTENSITY_MEDIUM;
         }
+        synchronized (mLock) {
+            if (mVibrator != null) {
+                if (isRingtone(usageHint)) {
+                    return mVibrator.getDefaultRingVibrationIntensity();
+                } else if (isNotification(usageHint)) {
+                    return mVibrator.getDefaultNotificationVibrationIntensity();
+                } else if (isHapticFeedback(usageHint)) {
+                    return mVibrator.getDefaultHapticFeedbackIntensity();
+                }
+            }
+        }
+        return Vibrator.VIBRATION_INTENSITY_MEDIUM;
     }
 
     /**
@@ -234,8 +251,11 @@
         if (!isRingtone(usageHint)) {
             return true;
         }
-        int ringerMode = mAudioManager.getRingerModeInternal();
         synchronized (mLock) {
+            if (mAudioManager == null) {
+                return false;
+            }
+            int ringerMode = mAudioManager.getRingerModeInternal();
             if (mVibrateWhenRinging) {
                 return ringerMode != AudioManager.RINGER_MODE_SILENT;
             } else if (mApplyRampingRinger) {
@@ -304,12 +324,12 @@
             mVibrateWhenRinging = getSystemSetting(Settings.System.VIBRATE_WHEN_RINGING, 0) != 0;
             mApplyRampingRinger = getGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0) != 0;
             mHapticFeedbackIntensity = getSystemSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
-                    mVibrator.getDefaultHapticFeedbackIntensity());
+                    getDefaultIntensity(VibrationAttributes.USAGE_TOUCH));
             mNotificationIntensity = getSystemSetting(
                     Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
-                    mVibrator.getDefaultNotificationVibrationIntensity());
+                    getDefaultIntensity(VibrationAttributes.USAGE_NOTIFICATION));
             mRingIntensity = getSystemSetting(Settings.System.RING_VIBRATION_INTENSITY,
-                    mVibrator.getDefaultRingVibrationIntensity());
+                    getDefaultIntensity(VibrationAttributes.USAGE_RINGTONE));
             mVibrateInputDevices = getSystemSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0) > 0;
             mZenMode = getGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
         }
@@ -346,15 +366,15 @@
             proto.write(VibratorManagerServiceDumpProto.HAPTIC_FEEDBACK_INTENSITY,
                     mHapticFeedbackIntensity);
             proto.write(VibratorManagerServiceDumpProto.HAPTIC_FEEDBACK_DEFAULT_INTENSITY,
-                    mVibrator.getDefaultHapticFeedbackIntensity());
+                    getDefaultIntensity(VibrationAttributes.USAGE_TOUCH));
             proto.write(VibratorManagerServiceDumpProto.NOTIFICATION_INTENSITY,
                     mNotificationIntensity);
             proto.write(VibratorManagerServiceDumpProto.NOTIFICATION_DEFAULT_INTENSITY,
-                    mVibrator.getDefaultNotificationVibrationIntensity());
+                    getDefaultIntensity(VibrationAttributes.USAGE_NOTIFICATION));
             proto.write(VibratorManagerServiceDumpProto.RING_INTENSITY,
                     mRingIntensity);
             proto.write(VibratorManagerServiceDumpProto.RING_DEFAULT_INTENSITY,
-                    mVibrator.getDefaultRingVibrationIntensity());
+                    getDefaultIntensity(VibrationAttributes.USAGE_RINGTONE));
         }
     }
 
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 1750854..90a763c 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -127,9 +127,9 @@
     @GuardedBy("mLock")
     private ExternalVibrationHolder mCurrentExternalVibration;
 
-    private VibrationSettings mVibrationSettings;
-    private VibrationScaler mVibrationScaler;
-    private InputDeviceDelegate mInputDeviceDelegate;
+    private final VibrationSettings mVibrationSettings;
+    private final VibrationScaler mVibrationScaler;
+    private final InputDeviceDelegate mInputDeviceDelegate;
 
     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
         @Override
@@ -170,6 +170,10 @@
         mContext = context;
         mHandler = injector.createHandler(Looper.myLooper());
 
+        mVibrationSettings = new VibrationSettings(mContext, mHandler);
+        mVibrationScaler = new VibrationScaler(mContext, mVibrationSettings);
+        mInputDeviceDelegate = new InputDeviceDelegate(mContext, mHandler);
+
         VibrationCompleteListener listener = new VibrationCompleteListener(this);
         mNativeWrapper = injector.getNativeWrapper();
         mNativeWrapper.init(listener);
@@ -224,12 +228,12 @@
         Slog.v(TAG, "Initializing VibratorManager service...");
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "systemReady");
         try {
-            mVibrationSettings = new VibrationSettings(mContext, mHandler);
-            mVibrationScaler = new VibrationScaler(mContext, mVibrationSettings);
-            mInputDeviceDelegate = new InputDeviceDelegate(mContext, mHandler);
+            mVibrationSettings.onSystemReady();
+            mInputDeviceDelegate.onSystemReady();
 
             mVibrationSettings.addListener(this::updateServiceState);
 
+            // Will update settings and input devices.
             updateServiceState();
         } finally {
             Slog.v(TAG, "VibratorManager service initialized");
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 3bbc81a..e6d37b6 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -1861,7 +1861,7 @@
         }
 
         @Override
-        public boolean isEnabled() {
+        public boolean isAccessibilityTracingEnabled() {
             return mTracing.isEnabled();
         }
 
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 151895f..c830ba9 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -808,7 +808,7 @@
 
                 if (rootTask.inFreeformWindowingMode()) {
                     rootTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
-                } else if (!mService.mSizeCompatFreeform && r.inSizeCompatMode()) {
+                } else if (!mService.mSupportsNonResizableMultiWindow && r.inSizeCompatMode()) {
                     throw new IllegalStateException("Size-compat windows are currently not"
                             + "freeform-enabled");
                 } else if (rootTask.getParent().inFreeformWindowingMode()) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 5d3b9c1..5932388 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -40,8 +40,11 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.activityTypeToString;
+import static android.app.WindowConfiguration.isSplitScreenWindowingMode;
 import static android.app.servertransaction.TransferSplashScreenViewStateItem.ATTACH_TO;
 import static android.app.servertransaction.TransferSplashScreenViewStateItem.HANDOVER_TO;
 import static android.content.Intent.ACTION_MAIN;
@@ -129,7 +132,6 @@
 import static com.android.server.wm.ActivityRecordProto.DEFER_HIDING_CLIENT;
 import static com.android.server.wm.ActivityRecordProto.FILLS_PARENT;
 import static com.android.server.wm.ActivityRecordProto.FRONT_OF_TASK;
-import static com.android.server.wm.ActivityRecordProto.FROZEN_BOUNDS;
 import static com.android.server.wm.ActivityRecordProto.IS_ANIMATING;
 import static com.android.server.wm.ActivityRecordProto.IS_WAITING_FOR_TRANSITION_START;
 import static com.android.server.wm.ActivityRecordProto.LAST_ALL_DRAWN;
@@ -209,6 +211,7 @@
 import static com.android.server.wm.WindowManagerService.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND;
 import static com.android.server.wm.WindowManagerService.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING;
 import static com.android.server.wm.WindowManagerService.LETTERBOX_BACKGROUND_SOLID_COLOR;
+import static com.android.server.wm.WindowManagerService.MIN_TASK_LETTERBOX_ASPECT_RATIO;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
 import static com.android.server.wm.WindowState.LEGACY_POLICY_VISIBILITY;
@@ -340,7 +343,6 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
-import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
@@ -557,7 +559,7 @@
 
     /**
      * The precomputed display insets for resolving configuration. It will be non-null if
-     * {@link #shouldUseSizeCompatMode} returns {@code true}.
+     * {@link #shouldCreateCompatDisplayInsets} returns {@code true}.
      */
     private CompatDisplayInsets mCompatDisplayInsets;
 
@@ -648,6 +650,18 @@
      */
     private Rect mSizeCompatBounds;
 
+    // Whether this activity is in size compatibility mode because its bounds don't fit in parent
+    // naturally.
+    private boolean mInSizeCompatModeForBounds = false;
+
+    // Whether this activity is letterboxed for fixed orientation. If letterboxed due to fixed
+    // orientation then aspect ratio restrictions are also already respected.
+    // This happens when an activity has fixed orientation which doesn't match orientation of the
+    // parent because a display is ignoring orientation request or fixed to user rotation.
+    // See WindowManagerService#getIgnoreOrientationRequest and
+    // WindowManagerService#getFixedToUserRotation for more context.
+    private boolean mIsLetterboxedForFixedOrientationAndAspectRatio = false;
+
     // activity is not displayed?
     // TODO: rename to mNoDisplay
     @VisibleForTesting
@@ -716,9 +730,6 @@
     // windows, where the app hasn't had time to set a value on the window.
     int mRotationAnimationHint = -1;
 
-    ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
-    ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>();
-
     private AppSaturationInfo mLastAppSaturationInfo;
 
     private final ColorDisplayService.ColorTransformController mColorTransformController =
@@ -747,6 +758,10 @@
     // Token for targeting this activity for assist purposes.
     final Binder assistToken = new Binder();
 
+    // A reusable token for other purposes, e.g. content capture, translation. It shouldn't be used
+    // without security checks
+    final Binder shareableActivityToken = new Binder();
+
     // Tracking cookie for the launch of this activity and it's task.
     IBinder mLaunchCookie;
 
@@ -1015,10 +1030,6 @@
             pw.println(" mVisibleSetFromTransferredStartingWindow="
                     + mVisibleSetFromTransferredStartingWindow);
         }
-        if (!mFrozenBounds.isEmpty()) {
-            pw.print(prefix); pw.print("mFrozenBounds="); pw.println(mFrozenBounds);
-            pw.print(prefix); pw.print("mFrozenMergedConfig="); pw.println(mFrozenMergedConfig);
-        }
         if (mPendingRelaunchCount != 0) {
             pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount);
         }
@@ -1296,9 +1307,6 @@
             // TODO(b/36505427): Maybe this call should be moved inside
             // updateOverrideConfiguration()
             newTask.updateOverrideConfigurationFromLaunchBounds();
-            // Make sure override configuration is up-to-date before using to create window
-            // controller.
-            updateSizeCompatMode();
             // When an activity is started directly into a split-screen fullscreen root task, we
             // need to update the initial multi-window modes so that the callbacks are scheduled
             // correctly when the user leaves that mode.
@@ -2549,9 +2557,7 @@
      *         root task.
      */
     boolean supportsFreeform() {
-        return mAtmService.mSupportsFreeformWindowManagement
-                // Either the activity is resizable, or we allow size compat in freeform.
-                && (supportsMultiWindow() || mAtmService.mSizeCompatFreeform);
+        return mAtmService.mSupportsFreeformWindowManagement && supportsMultiWindow();
     }
 
     /**
@@ -3344,56 +3350,18 @@
         return mPendingRelaunchCount > 0;
     }
 
-    boolean shouldFreezeBounds() {
-        // For freeform windows, we can't freeze the bounds at the moment because this would make
-        // the resizing unresponsive.
-        if (task == null || task.inFreeformWindowingMode()) {
-            return false;
-        }
-
-        // We freeze the bounds while drag resizing to deal with the time between
-        // the divider/drag handle being released, and the handling it's new
-        // configuration. If we are relaunched outside of the drag resizing state,
-        // we need to be careful not to do this.
-        return task.isDragResizing();
-    }
-
     @VisibleForTesting
     void startRelaunching() {
         if (mPendingRelaunchCount == 0) {
             mRelaunchStartTime = SystemClock.elapsedRealtime();
         }
-        if (shouldFreezeBounds()) {
-            freezeBounds();
-        }
-
         clearAllDrawn();
 
         mPendingRelaunchCount++;
     }
 
-    /**
-     * Freezes the task bounds. The size of this task reported the app will be fixed to the bounds
-     * freezed by {@link Task#prepareFreezingBounds} until {@link #unfreezeBounds} gets called, even
-     * if they change in the meantime. If the bounds are already frozen, the bounds will be frozen
-     * with a queue.
-     */
-    private void freezeBounds() {
-        mFrozenBounds.offer(new Rect(task.mPreparedFrozenBounds));
-
-        if (task.mPreparedFrozenMergedConfig.equals(Configuration.EMPTY)) {
-            // We didn't call prepareFreezingBounds on the task, so use the current value.
-            mFrozenMergedConfig.offer(new Configuration(task.getConfiguration()));
-        } else {
-            mFrozenMergedConfig.offer(new Configuration(task.mPreparedFrozenMergedConfig));
-        }
-        // Calling unset() to make it equal to Configuration.EMPTY.
-        task.mPreparedFrozenMergedConfig.unset();
-    }
-
     void finishRelaunching() {
         mTaskSupervisor.getActivityMetricsLogger().notifyActivityRelaunched(this);
-        unfreezeBounds();
 
         if (mPendingRelaunchCount > 0) {
             mPendingRelaunchCount--;
@@ -3415,30 +3383,11 @@
         if (mPendingRelaunchCount == 0) {
             return;
         }
-        unfreezeBounds();
         mPendingRelaunchCount = 0;
         mRelaunchStartTime = 0;
     }
 
     /**
-     * Unfreezes the previously frozen bounds. See {@link #freezeBounds}.
-     */
-    private void unfreezeBounds() {
-        if (mFrozenBounds.isEmpty()) {
-            return;
-        }
-        mFrozenBounds.remove();
-        if (!mFrozenMergedConfig.isEmpty()) {
-            mFrozenMergedConfig.remove();
-        }
-        for (int i = mChildren.size() - 1; i >= 0; i--) {
-            final WindowState win = mChildren.get(i);
-            win.onUnfreezeBounds();
-        }
-        mWmService.mWindowPlacerLocked.performSurfacePlacement();
-    }
-
-    /**
      * Perform clean-up of service connections in an activity record.
      */
     private void cleanUpActivityServices() {
@@ -3624,7 +3573,7 @@
         }
 
         // Reset the last saved PiP snap fraction on removal.
-        mDisplayContent.mPinnedStackControllerLocked.onActivityHidden(mActivityComponent);
+        mDisplayContent.mPinnedTaskControllerLocked.onActivityHidden(mActivityComponent);
         mWmService.mEmbeddedWindowController.onActivityRemoved(this);
         mRemovingFromDisplay = false;
     }
@@ -4434,6 +4383,7 @@
             return;
         }
         mVisibleRequested = visible;
+        setInsetsFrozen(!visible);
         if (app != null) {
             mTaskSupervisor.onProcessActivityStateChanged(app, false /* forceBatch */);
         }
@@ -4976,7 +4926,7 @@
         ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppStopped: %s", this);
         mAppStopped = true;
         // Reset the last saved PiP snap fraction on app stop.
-        mDisplayContent.mPinnedStackControllerLocked.onActivityHidden(mActivityComponent);
+        mDisplayContent.mPinnedTaskControllerLocked.onActivityHidden(mActivityComponent);
         destroySurfaces();
         // Remove any starting window that was added for this app if they are still around.
         removeStartingWindow();
@@ -6718,12 +6668,8 @@
         }
 
         if (onDescendantOrientationChanged(this)) {
-            // The app is just becoming visible, and the parent Task has updated with the
-            // orientation request. Update the size compat mode.
-            updateSizeCompatMode();
-            // WM Shell can override WM Core positioning (e.g. for letterboxing) so ensure
-            // that WM Shell is called when an activity becomes visible. Without this, WM Core
-            // will handle positioning instead of WM Shell when an app is reopened.
+            // WM Shell can show additional UI elements, e.g. a restart button for size compat mode
+            // so ensure that WM Shell is called when an activity becomes visible.
             task.dispatchTaskInfoChangedIfNeeded(/* force= */ true);
         }
     }
@@ -6788,7 +6734,10 @@
      *         density than its parent or its bounds don't fit in parent naturally.
      */
     boolean inSizeCompatMode() {
-        if (mCompatDisplayInsets == null || !shouldUseSizeCompatMode()
+        if (mInSizeCompatModeForBounds) {
+            return true;
+        }
+        if (mCompatDisplayInsets == null || !shouldCreateCompatDisplayInsets()
                 // The orientation is different from parent when transforming.
                 || isFixedRotationTransforming()) {
             return false;
@@ -6798,70 +6747,30 @@
             // The app bounds hasn't been computed yet.
             return false;
         }
-
         final Configuration parentConfig = getParent().getConfiguration();
         // Although colorMode, screenLayout, smallestScreenWidthDp are also fixed, generally these
         // fields should be changed with density and bounds, so here only compares the most
         // significant field.
-        if (parentConfig.densityDpi != getConfiguration().densityDpi) {
-            return true;
-        }
-
-        final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds();
-        final int appWidth = appBounds.width();
-        final int appHeight = appBounds.height();
-        final int parentAppWidth = parentAppBounds.width();
-        final int parentAppHeight = parentAppBounds.height();
-        if (parentAppWidth == appWidth && parentAppHeight == appHeight) {
-            // Matched the parent bounds.
-            return false;
-        }
-        if (parentAppWidth > appWidth && parentAppHeight > appHeight) {
-            // Both sides are smaller than the parent.
-            return true;
-        }
-        if (parentAppWidth < appWidth || parentAppHeight < appHeight) {
-            // One side is larger than the parent.
-            return true;
-        }
-
-        // The rest of the condition is that only one side is smaller than the parent, but it still
-        // needs to exclude the cases where the size is limited by the fixed aspect ratio.
-        if (info.maxAspectRatio > 0) {
-            final float aspectRatio = (0.5f + Math.max(appWidth, appHeight))
-                    / Math.min(appWidth, appHeight);
-            if (aspectRatio >= info.maxAspectRatio) {
-                // The current size has reached the max aspect ratio.
-                return false;
-            }
-        }
-        if (info.minAspectRatio > 0) {
-            // The activity should have at least the min aspect ratio, so this checks if the parent
-            // still has available space to provide larger aspect ratio.
-            final float parentAspectRatio = (0.5f + Math.max(parentAppWidth, parentAppHeight))
-                    / Math.min(parentAppWidth, parentAppHeight);
-            if (parentAspectRatio <= info.minAspectRatio) {
-                // The long side has reached the parent.
-                return false;
-            }
-        }
-        return true;
+        return parentConfig.densityDpi != getConfiguration().densityDpi;
     }
 
     /**
      * Indicates the activity will keep the bounds and screen configuration when it was first
      * launched, no matter how its parent changes.
      *
+     * <p>If {@true}, then {@link CompatDisplayInsets} will be created in {@link
+     * #resolveOverrideConfiguration} to "freeze" activity bounds and insets.
+     *
      * @return {@code true} if this activity is declared as non-resizable and fixed orientation or
      *         aspect ratio.
      */
-    boolean shouldUseSizeCompatMode() {
+    boolean shouldCreateCompatDisplayInsets() {
         if (info.supportsSizeChanges() != ActivityInfo.SIZE_CHANGES_UNSUPPORTED) {
             return false;
         }
         if (inMultiWindowMode() || getWindowConfiguration().hasWindowDecorCaption()) {
             final ActivityRecord root = task != null ? task.getRootActivity() : null;
-            if (root != null && root != this && !root.shouldUseSizeCompatMode()) {
+            if (root != null && root != this && !root.shouldCreateCompatDisplayInsets()) {
                 // If the root activity doesn't use size compatibility mode, the activities above
                 // are forced to be the same for consistent visual appearance.
                 return false;
@@ -6883,25 +6792,11 @@
     }
 
     // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
-    private void updateSizeCompatMode() {
-        if (mCompatDisplayInsets != null || !shouldUseSizeCompatMode()) {
+    private void updateCompatDisplayInsets(@Nullable Rect fixedOrientationBounds) {
+        if (mCompatDisplayInsets != null || !shouldCreateCompatDisplayInsets()) {
             // The override configuration is set only once in size compatibility mode.
             return;
         }
-        final Configuration parentConfig = getParent().getConfiguration();
-        if (!hasProcess() && !isConfigurationCompatible(parentConfig)) {
-            // Don't compute when launching in fullscreen and the fixed orientation is not the
-            // current orientation. It is more accurately to compute the override bounds from
-            // the updated configuration after the fixed orientation is applied.
-            return;
-        }
-
-        if (task == null || (!handlesOrientationChangeFromDescendant()
-                && task.getLastTaskBoundsComputeActivity() != this)) {
-            // Don't compute when Task hasn't computed its bounds for this app, because the Task can
-            // be letterboxed, and its bounds may not be accurate until then.
-            return;
-        }
 
         Configuration overrideConfig = getRequestedOverrideConfiguration();
         final Configuration fullConfig = getConfiguration();
@@ -6924,17 +6819,18 @@
         }
 
         // The role of CompatDisplayInsets is like the override bounds.
-        mCompatDisplayInsets = new CompatDisplayInsets(mDisplayContent, this);
+        mCompatDisplayInsets =
+                new CompatDisplayInsets(mDisplayContent, this, fixedOrientationBounds);
     }
 
     @VisibleForTesting
     void clearSizeCompatMode() {
+        mInSizeCompatModeForBounds = false;
         mSizeCompatScale = 1f;
         mSizeCompatBounds = null;
         mCompatDisplayInsets = null;
 
-        // Recompute from Task because letterbox can also happen on Task level.
-        task.onRequestedOverrideConfigurationChanged(task.getRequestedOverrideConfiguration());
+        onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration());
     }
 
     @Override
@@ -6969,23 +6865,41 @@
             mTmpConfig.updateFrom(resolvedConfig);
             newParentConfiguration = mTmpConfig;
         }
+
+        final int windowingMode = getWindowingMode();
+        // TODO(b/181207944): Consider removing the if condition and always run
+        // resolveFixedOrientationConfiguration() since this should be applied for all cases.
+        if (isSplitScreenWindowingMode(windowingMode)
+                || windowingMode == WINDOWING_MODE_MULTI_WINDOW
+                || windowingMode == WINDOWING_MODE_FULLSCREEN) {
+            resolveFixedOrientationConfiguration(newParentConfiguration);
+        }
+        final Rect fixedOrientationBounds = isLetterboxedForFixedOrientationAndAspectRatio()
+                ? new Rect(resolvedConfig.windowConfiguration.getBounds()) : null;
+
         if (mCompatDisplayInsets != null) {
             resolveSizeCompatModeConfiguration(newParentConfiguration);
-        } else {
-            if (inMultiWindowMode()) {
-                // We ignore activities' requested orientation in multi-window modes. Task level may
-                // take them into consideration when calculating bounds.
-                resolvedConfig.orientation = Configuration.ORIENTATION_UNDEFINED;
-                // If the activity has requested override bounds, the configuration needs to be
-                // computed accordingly.
-                if (!matchParentBounds()) {
-                    task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration);
-                }
-            } else {
-                resolveFullscreenConfiguration(newParentConfiguration);
+        } else if (inMultiWindowMode()) {
+            // We ignore activities' requested orientation in multi-window modes. They may be
+            // taken into consideration in resolveFixedOrientationConfiguration call above.
+            resolvedConfig.orientation = Configuration.ORIENTATION_UNDEFINED;
+            // If the activity has requested override bounds, the configuration needs to be
+            // computed accordingly.
+            if (!matchParentBounds()) {
+                task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration);
             }
+        // If activity in fullscreen mode is letterboxed because of fixed orientation then bounds
+        // are already calculated in resolveFixedOrientationConfiguration.
+        } else if (!isLetterboxedForFixedOrientationAndAspectRatio()) {
+            resolveFullscreenConfiguration(newParentConfiguration);
         }
 
+        if (mVisibleRequested) {
+            updateCompatDisplayInsets(fixedOrientationBounds);
+        }
+
+        // TODO(b/175212232): Consolidate position logic from each "resolve" method above here.
+
         // Assign configuration sequence number into hierarchy because there is a different way than
         // ensureActivityConfiguration() in this class that uses configuration in WindowState during
         // layout traversals.
@@ -6994,6 +6908,109 @@
     }
 
     /**
+     * Whether this activity is letterboxed for fixed orientation. If letterboxed due to fixed
+     * orientation then aspect ratio restrictions are also already respected.
+     *
+     * <p>This happens when an activity has fixed orientation which doesn't match orientation of the
+     * parent because a display setting 'ignoreOrientationRequest' is set to true. See {@link
+     * WindowManagerService#getIgnoreOrientationRequest} for more context.
+     */
+    boolean isLetterboxedForFixedOrientationAndAspectRatio() {
+        return mIsLetterboxedForFixedOrientationAndAspectRatio;
+    }
+
+    /**
+     * Computes bounds (letterbox or pillarbox) when the parent doesn't handle the orientation
+     * change and the requested orientation is different from the parent.
+     *
+     * <p>If letterboxed due to fixed orientation then aspect ratio restrictions are also applied
+     * in this methiod.
+     */
+    private void resolveFixedOrientationConfiguration(@NonNull Configuration newParentConfig) {
+        mIsLetterboxedForFixedOrientationAndAspectRatio = false;
+        if (handlesOrientationChangeFromDescendant()) {
+            // No need to letterbox because of fixed orientation. Display will handle
+            // fixed-orientation requests.
+            return;
+        }
+
+        final Rect resolvedBounds =
+                getResolvedOverrideConfiguration().windowConfiguration.getBounds();
+        final int parentOrientation = newParentConfig.orientation;
+
+        // If the activity requires a different orientation (either by override or activityInfo),
+        // make it fit the available bounds by scaling down its bounds.
+        final int forcedOrientation = getRequestedConfigurationOrientation();
+        if (forcedOrientation == ORIENTATION_UNDEFINED || forcedOrientation == parentOrientation) {
+            return;
+        }
+
+        if (mCompatDisplayInsets != null && !mCompatDisplayInsets.mIsInFixedOrientationLetterbox) {
+            // App prefers to keep its original size.
+            // If the size compat is from previous fixed orientation letterboxing, we may want to
+            // have fixed orientation letterbox again, otherwise it will show the size compat
+            // restart button even if the restart bounds will be the same.
+            return;
+        }
+
+        final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
+        final int parentWidth = parentBounds.width();
+        final int parentHeight = parentBounds.height();
+        float aspect = Math.max(parentWidth, parentHeight)
+                / (float) Math.min(parentWidth, parentHeight);
+
+        // Adjust the fixed orientation letterbox bounds to fit the app request aspect ratio in
+        // order to use the extra available space.
+        final float maxAspectRatio = info.maxAspectRatio;
+        final float minAspectRatio = info.minAspectRatio;
+        if (aspect > maxAspectRatio && maxAspectRatio != 0) {
+            aspect = maxAspectRatio;
+        } else if (aspect < minAspectRatio) {
+            aspect = minAspectRatio;
+        }
+
+        // Override from config_letterboxAspectRatio or via ADB with set-letterbox-aspect-ratio.
+        // TODO(b/175212232): Rename getTaskLetterboxAspectRatio and all related methods since fixed
+        // orientation letterbox is on the activity level now.
+        final float letterboxAspectRatioOverride = mWmService.getTaskLetterboxAspectRatio();
+        // Activity min/max aspect ratio restrictions will be respected by the activity-level
+        // letterboxing (size-compat mode). Therefore this override can control the maximum screen
+        // area that can be occupied by the app in the letterbox mode.
+        aspect = letterboxAspectRatioOverride > MIN_TASK_LETTERBOX_ASPECT_RATIO
+                ? letterboxAspectRatioOverride : aspect;
+
+        // Store the current bounds to be able to revert to size compat mode values below if needed.
+        Rect mTmpFullBounds = new Rect(resolvedBounds);
+        if (forcedOrientation == ORIENTATION_LANDSCAPE) {
+            final int height = (int) Math.rint(parentWidth / aspect);
+            final int top = parentBounds.centerY() - height / 2;
+            resolvedBounds.set(parentBounds.left, top, parentBounds.right, top + height);
+        } else {
+            final int width = (int) Math.rint(parentHeight / aspect);
+            final int left = parentBounds.centerX() - width / 2;
+            resolvedBounds.set(left, parentBounds.top, left + width, parentBounds.bottom);
+        }
+
+        if (mCompatDisplayInsets != null) {
+            mCompatDisplayInsets.getBoundsByRotation(
+                    mTmpBounds, newParentConfig.windowConfiguration.getRotation());
+            if (resolvedBounds.width() != mTmpBounds.width()
+                    || resolvedBounds.height() != mTmpBounds.height()) {
+                // The app shouldn't be resized, we only do fixed orientation letterboxing if the
+                // compat bounds are also from the same fixed orientation letterbox. Otherwise,
+                // clear the fixed orientation bounds to show app in size compat mode.
+                resolvedBounds.set(mTmpFullBounds);
+                return;
+            }
+        }
+
+        // Calculate app bounds using fixed orientation bounds because they will be needed later
+        // for comparison with size compat app bounds in {@link resolveSizeCompatModeConfiguration}.
+        task.computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
+        mIsLetterboxedForFixedOrientationAndAspectRatio = true;
+    }
+
+    /**
      * Resolves the configuration of activity in fullscreen mode. If the bounds are restricted by
      * aspect ratio, the position will be centered horizontally in parent's app bounds to balance
      * the visual appearance. The policy of aspect ratio has higher priority than the requested
@@ -7037,6 +7054,18 @@
     private void resolveSizeCompatModeConfiguration(Configuration newParentConfiguration) {
         final Configuration resolvedConfig = getResolvedOverrideConfiguration();
         final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
+
+        // When an activity needs to be letterboxed because of fixed orientation, use fixed
+        // orientation bounds (stored in resolved bounds) instead of parent bounds since the
+        // activity will be displayed within them even if it is in size compat mode. They should be
+        // saved here before resolved bounds are overridden below.
+        final Rect containerBounds = isLetterboxedForFixedOrientationAndAspectRatio()
+                ? new Rect(resolvedBounds)
+                : newParentConfiguration.windowConfiguration.getBounds();
+        final Rect containerAppBounds = isLetterboxedForFixedOrientationAndAspectRatio()
+                ? new Rect(getResolvedOverrideConfiguration().windowConfiguration.getAppBounds())
+                : newParentConfiguration.windowConfiguration.getAppBounds();
+
         final int requestedOrientation = getRequestedConfigurationOrientation();
         final boolean orientationRequested = requestedOrientation != ORIENTATION_UNDEFINED;
         final int orientation = orientationRequested
@@ -7095,7 +7124,7 @@
         // Below figure is an example that puts an activity which was launched in a larger container
         // into a smaller container.
         //   The outermost rectangle is the real display bounds.
-        //   "@" is the parent app bounds.
+        //   "@" is the container app bounds (parent bounds or fixed orientation bouds)
         //   "#" is the {@code resolvedBounds} that applies to application.
         //   "*" is the {@code mSizeCompatBounds} that used to show on screen if scaled.
         // ------------------------------
@@ -7111,19 +7140,18 @@
         // The application is still layouted in "#" since it was launched, and it will be visually
         // scaled and positioned to "*".
 
+        final Rect resolvedAppBounds = resolvedConfig.windowConfiguration.getAppBounds();
+
         // Calculates the scale and offset to horizontal center the size compatibility bounds into
         // the region which is available to application.
-        final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
-        final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds();
-        final Rect resolvedAppBounds = resolvedConfig.windowConfiguration.getAppBounds();
         final int contentW = resolvedAppBounds.width();
         final int contentH = resolvedAppBounds.height();
-        final int viewportW = parentAppBounds.width();
-        final int viewportH = parentAppBounds.height();
+        final int viewportW = containerAppBounds.width();
+        final int viewportH = containerAppBounds.height();
         // Only allow to scale down.
         mSizeCompatScale = (contentW <= viewportW && contentH <= viewportH)
                 ? 1f : Math.min((float) viewportW / contentW, (float) viewportH / contentH);
-        final int screenTopInset = parentAppBounds.top - parentBounds.top;
+        final int screenTopInset = containerAppBounds.top - containerBounds.top;
         final boolean topNotAligned = screenTopInset != resolvedAppBounds.top - resolvedBounds.top;
         if (mSizeCompatScale != 1f || topNotAligned) {
             if (mSizeCompatBounds == null) {
@@ -7143,8 +7171,9 @@
         final int offsetX = getHorizontalCenterOffset(
                 (int) viewportW, (int) (contentW * mSizeCompatScale));
         // Above coordinates are in "@" space, now place "*" and "#" to screen space.
-        final int screenPosX = (fillContainer ? parentBounds.left : parentAppBounds.left) + offsetX;
-        final int screenPosY = parentBounds.top;
+        final int screenPosX = (fillContainer
+                ? containerBounds.left : containerAppBounds.left) + offsetX;
+        final int screenPosY = containerBounds.top;
         if (screenPosX != 0 || screenPosY != 0) {
             if (mSizeCompatBounds != null) {
                 mSizeCompatBounds.offset(screenPosX, screenPosY);
@@ -7154,6 +7183,52 @@
             final int dy = screenPosY - resolvedBounds.top;
             offsetBounds(resolvedConfig, dx, dy);
         }
+
+        mInSizeCompatModeForBounds =
+                isInSizeCompatModeForBounds(resolvedAppBounds, containerAppBounds);
+    }
+
+    private boolean isInSizeCompatModeForBounds(final Rect appBounds, final Rect containerBounds) {
+        final int appWidth = appBounds.width();
+        final int appHeight = appBounds.height();
+        final int containerAppWidth = containerBounds.width();
+        final int containerAppHeight = containerBounds.height();
+
+        if (containerAppWidth == appWidth && containerAppHeight == appHeight) {
+            // Matched the container bounds.
+            return false;
+        }
+        if (containerAppWidth > appWidth && containerAppHeight > appHeight) {
+            // Both sides are smaller than the container.
+            return true;
+        }
+        if (containerAppWidth < appWidth || containerAppHeight < appHeight) {
+            // One side is larger than the container.
+            return true;
+        }
+
+        // The rest of the condition is that only one side is smaller than the container, but it
+        // still needs to exclude the cases where the size is limited by the fixed aspect ratio.
+        if (info.maxAspectRatio > 0) {
+            final float aspectRatio = (0.5f + Math.max(appWidth, appHeight))
+                    / Math.min(appWidth, appHeight);
+            if (aspectRatio >= info.maxAspectRatio) {
+                // The current size has reached the max aspect ratio.
+                return false;
+            }
+        }
+        if (info.minAspectRatio > 0) {
+            // The activity should have at least the min aspect ratio, so this checks if the
+            // container still has available space to provide larger aspect ratio.
+            final float containerAspectRatio =
+                    (0.5f + Math.max(containerAppWidth, containerAppHeight))
+                            / Math.min(containerAppWidth, containerAppHeight);
+            if (containerAspectRatio <= info.minAspectRatio) {
+                // The long side has reached the parent.
+                return false;
+            }
+        }
+        return true;
     }
 
     /** @return The horizontal offset of putting the content in the center of viewport. */
@@ -7305,7 +7380,8 @@
         final Task rootTask = getRootTask();
         final float minAspectRatio = info.minAspectRatio;
 
-        if (task == null || rootTask == null || (inMultiWindowMode() && !shouldUseSizeCompatMode())
+        if (task == null || rootTask == null
+                || (inMultiWindowMode() && !shouldCreateCompatDisplayInsets())
                 || (maxAspectRatio == 0 && minAspectRatio == 0)
                 || isInVrUiMode(getConfiguration())) {
             // We don't enforce aspect ratio if the activity task is in multiwindow unless it
@@ -7443,8 +7519,6 @@
         if (displayChanged) {
             mLastReportedDisplayId = newDisplayId;
         }
-        // TODO(b/36505427): Is there a better place to do this?
-        updateSizeCompatMode();
 
         // Short circuit: if the two full configurations are equal (the common case), then there is
         // nothing to do.  We test the full configuration instead of the global and merged override
@@ -7723,11 +7797,6 @@
         // Reset the existing override configuration so it can be updated according to the latest
         // configuration.
         clearSizeCompatMode();
-        if (mVisibleRequested) {
-            // Configuration will be ensured when becoming visible, so if it is already visible,
-            // then the manual update is needed.
-            updateSizeCompatMode();
-        }
 
         if (!attachedToProcess()) {
             return;
@@ -8080,9 +8149,6 @@
         proto.write(STARTING_MOVED, startingMoved);
         proto.write(VISIBLE_SET_FROM_TRANSFERRED_STARTING_WINDOW,
                 mVisibleSetFromTransferredStartingWindow);
-        for (Rect bounds : mFrozenBounds) {
-            bounds.dumpDebug(proto, FROZEN_BOUNDS);
-        }
 
         proto.write(STATE, mState.toString());
         proto.write(FRONT_OF_TASK, isRootOfTask());
@@ -8134,8 +8200,11 @@
         private final int mHeight;
         /** Whether the {@link Task} windowingMode represents a floating window*/
         final boolean mIsFloating;
-        /** Whether the {@link Task} is letterboxed when the unresizable activity is first shown. */
-        final boolean mIsTaskLetterboxed;
+        /**
+         * Whether is letterboxed because of fixed orientation when the unresizable activity is
+         * first shown.
+         */
+        final boolean mIsInFixedOrientationLetterbox;
         /**
          * The nonDecorInsets for each rotation. Includes the navigation bar and cutout insets. It
          * is used to compute the appBounds.
@@ -8149,7 +8218,8 @@
         final Rect[] mStableInsets = new Rect[4];
 
         /** Constructs the environment to simulate the bounds behavior of the given container. */
-        CompatDisplayInsets(DisplayContent display, ActivityRecord container) {
+        CompatDisplayInsets(DisplayContent display, ActivityRecord container,
+                @Nullable Rect fixedOrientationBounds) {
             mIsFloating = container.getWindowConfiguration().tasksAreFloating();
             if (mIsFloating) {
                 final Rect containerBounds = container.getWindowConfiguration().getBounds();
@@ -8162,24 +8232,34 @@
                     mNonDecorInsets[rotation] = emptyRect;
                     mStableInsets[rotation] = emptyRect;
                 }
-                mIsTaskLetterboxed = false;
+                mIsInFixedOrientationLetterbox = false;
                 return;
             }
 
             final Task task = container.getTask();
-            mIsTaskLetterboxed = task != null && task.isTaskLetterboxed();
+
+            mIsInFixedOrientationLetterbox = fixedOrientationBounds != null;
 
             // Store the bounds of the Task for the non-resizable activity to use in size compat
             // mode so that the activity will not be resized regardless the windowing mode it is
             // currently in.
-            final WindowContainer filledContainer = task != null ? task : display;
-            final Point dimensions = getRotationZeroDimensions(filledContainer);
+            // When an activity needs to be letterboxed because of fixed orientation, use fixed
+            // orientation bounds instead of task bounds since the activity will be displayed
+            // within these even if it is in size compat mode.
+            final Rect filledContainerBounds = mIsInFixedOrientationLetterbox
+                    ? fixedOrientationBounds
+                    : task != null ? task.getBounds() : display.getBounds();
+            final int filledContainerRotation = task != null
+                    ? task.getConfiguration().windowConfiguration.getRotation()
+                    : display.getConfiguration().windowConfiguration.getRotation();
+            final Point dimensions = getRotationZeroDimensions(
+                    filledContainerBounds, filledContainerRotation);
             mWidth = dimensions.x;
             mHeight = dimensions.y;
 
             // Bounds of the filled container if it doesn't fill the display.
             final Rect unfilledContainerBounds =
-                    filledContainer.getBounds().equals(display.getBounds()) ? null : new Rect();
+                    filledContainerBounds.equals(display.getBounds()) ? null : new Rect();
             final DisplayPolicy policy = display.getDisplayPolicy();
             for (int rotation = 0; rotation < 4; rotation++) {
                 mNonDecorInsets[rotation] = new Rect();
@@ -8199,9 +8279,9 @@
                 // The insets is based on the display, but the container may be smaller than the
                 // display, so update the insets to exclude parts that are not intersected with the
                 // container.
-                unfilledContainerBounds.set(filledContainer.getBounds());
+                unfilledContainerBounds.set(filledContainerBounds);
                 display.rotateBounds(
-                        filledContainer.getConfiguration().windowConfiguration.getRotation(),
+                        filledContainerRotation,
                         rotation,
                         unfilledContainerBounds);
                 updateInsetsForBounds(unfilledContainerBounds, dw, dh, mNonDecorInsets[rotation]);
@@ -8214,9 +8294,7 @@
          * the display is rotated, we can calculate the bounds by rotating the dimensions.
          * @see #getBoundsByRotation
          */
-        private static Point getRotationZeroDimensions(WindowContainer container) {
-            final Rect bounds = container.getBounds();
-            final int rotation = container.getConfiguration().windowConfiguration.getRotation();
+        private static Point getRotationZeroDimensions(final Rect bounds, int rotation) {
             final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
             final int width = bounds.width();
             final int height = bounds.height();
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 60ca725..6ce9048 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1708,7 +1708,7 @@
 
         // If the activity being launched is the same as the one currently at the top, then
         // we need to check if it should only be launched once.
-        final Task topRootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
+        final Task topRootTask = mPreferredTaskDisplayArea.getFocusedRootTask();
         if (topRootTask != null) {
             startResult = deliverToCurrentTopIfNeeded(topRootTask, intentGrants);
             if (startResult != START_SUCCESS) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 94379b1..e858fe1 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -348,13 +348,16 @@
     public final class ActivityTokens {
         private final @NonNull IBinder mActivityToken;
         private final @NonNull IBinder mAssistToken;
+        private final @NonNull IBinder mShareableActivityToken;
         private final @NonNull IApplicationThread mAppThread;
 
         public ActivityTokens(@NonNull IBinder activityToken,
-                @NonNull IBinder assistToken, @NonNull IApplicationThread appThread) {
+                @NonNull IBinder assistToken, @NonNull IApplicationThread appThread,
+                @NonNull IBinder shareableActivityToken) {
             mActivityToken = activityToken;
             mAssistToken = assistToken;
             mAppThread = appThread;
+            mShareableActivityToken = shareableActivityToken;
         }
 
         /**
@@ -372,6 +375,13 @@
         }
 
         /**
+         * @return The sharable activity token..
+         */
+        public @NonNull IBinder getShareableActivityToken() {
+            return mShareableActivityToken;
+        }
+
+        /**
          * @return The assist token.
          */
         public @NonNull IApplicationThread getApplicationThread() {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index b803fc3..0c77d9f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -58,7 +58,6 @@
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW;
-import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL;
 import static android.provider.Settings.Global.HIDE_ERROR_DIALOGS;
@@ -557,7 +556,6 @@
     boolean mSupportsPictureInPicture;
     boolean mSupportsMultiDisplay;
     boolean mForceResizableActivities;
-    boolean mSizeCompatFreeform;
     boolean mSupportsNonResizableMultiWindow;
 
     final List<ActivityTaskManagerInternal.ScreenObserver> mScreenObservers = new ArrayList<>();
@@ -788,8 +786,6 @@
         final boolean forceRtl = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_RTL, 0) != 0;
         final boolean forceResizable = Settings.Global.getInt(
                 resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
-        final boolean sizeCompatFreeform = Settings.Global.getInt(
-                resolver, DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM, 0) != 0;
         final boolean supportsNonResizableMultiWindow = Settings.Global.getInt(
                 resolver, DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, 1) != 0;
 
@@ -805,7 +801,6 @@
 
         synchronized (mGlobalLock) {
             mForceResizableActivities = forceResizable;
-            mSizeCompatFreeform = sizeCompatFreeform;
             mSupportsNonResizableMultiWindow = supportsNonResizableMultiWindow;
             final boolean multiWindowFormEnabled = freeformWindowManagement
                     || supportsSplitScreenMultiWindow
@@ -2095,10 +2090,14 @@
         }
     }
 
-    /** @return the max ANR delay from all registered {@link AnrController} instances */
-    public long getMaxAnrDelayMillis(ApplicationInfo info) {
+    /**
+     * @return the controller with the max ANR delay from all registered
+     * {@link AnrController} instances
+     */
+    @Nullable
+    public AnrController getAnrController(ApplicationInfo info) {
         if (info == null || info.packageName == null) {
-            return 0;
+            return null;
         }
 
         final ArrayList<AnrController> controllers;
@@ -2107,12 +2106,19 @@
         }
 
         final String packageName = info.packageName;
+        final int uid = info.uid;
         long maxDelayMs = 0;
+        AnrController controllerWithMaxDelay = null;
+
         for (AnrController controller : controllers) {
-            maxDelayMs = Math.max(maxDelayMs, controller.getAnrDelayMillis(packageName, info.uid));
+            long delayMs = controller.getAnrDelayMillis(packageName, uid);
+            if (delayMs > 0 && delayMs > maxDelayMs) {
+                controllerWithMaxDelay = controller;
+                maxDelayMs = delayMs;
+            }
         }
-        maxDelayMs = Math.max(maxDelayMs, 0);
-        return maxDelayMs;
+
+        return controllerWithMaxDelay;
     }
 
     @Override
@@ -4036,17 +4042,9 @@
     int updateGlobalConfigurationLocked(@NonNull Configuration values, boolean initLocale,
             boolean persistent, int userId) {
 
-        final DisplayContent defaultDisplay =
-                mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY);
-
         mTempConfig.setTo(getGlobalConfiguration());
         final int changes = mTempConfig.updateFrom(values);
         if (changes == 0) {
-            // Since calling to Activity.setRequestedOrientation leads to freezing the window with
-            // setting WindowManagerService.mWaitingForConfig to true, it is important that we call
-            // performDisplayOverrideConfigUpdate in order to send the new display configuration
-            // (even if there are no actual changes) to unfreeze the window.
-            defaultDisplay.performDisplayOverrideConfigUpdate(values);
             return 0;
         }
 
@@ -5544,7 +5542,7 @@
                     return null;
                 }
                 return new ActivityTokens(activity.appToken, activity.assistToken,
-                        activity.app.getThread());
+                        activity.app.getThread(), activity.shareableActivityToken);
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index bf2aae8..bb0f1f0 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -825,7 +825,7 @@
                         r.getSavedState(), r.getPersistentSavedState(), results, newIntents,
                         r.takeOptions(), dc.isNextTransitionForward(),
                         proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
-                        r.createFixedRotationAdjustmentsIfNeeded()));
+                        r.createFixedRotationAdjustmentsIfNeeded(), r.shareableActivityToken));
 
                 // Set desired final state.
                 final ActivityLifecycleItem lifecycleItem;
diff --git a/services/core/java/com/android/server/wm/BlurController.java b/services/core/java/com/android/server/wm/BlurController.java
new file mode 100644
index 0000000..13295e8
--- /dev/null
+++ b/services/core/java/com/android/server/wm/BlurController.java
@@ -0,0 +1,76 @@
+/*
+ * 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.wm;
+
+import static android.view.CrossWindowBlurListeners.CROSS_WINDOW_BLUR_SUPPORTED;
+
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.view.ICrossWindowBlurEnabledListener;
+
+final class BlurController {
+
+    private final RemoteCallbackList<ICrossWindowBlurEnabledListener>
+            mBlurEnabledListeners = new RemoteCallbackList<>();
+    private final Object mLock = new Object();
+    boolean mBlurEnabled;
+
+    BlurController() {
+        mBlurEnabled = CROSS_WINDOW_BLUR_SUPPORTED;
+    }
+
+    boolean registerCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener) {
+        if (listener == null) return false;
+        mBlurEnabledListeners.register(listener);
+        synchronized (mLock) {
+            return mBlurEnabled;
+        }
+    }
+
+    void unregisterCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener) {
+        if (listener == null) return;
+        mBlurEnabledListeners.unregister(listener);
+    }
+
+    private void updateBlurEnabled() {
+        // TODO: add other factors disabling blurs
+        final boolean newEnabled = CROSS_WINDOW_BLUR_SUPPORTED;
+        synchronized (mLock) {
+            if (mBlurEnabled == newEnabled) {
+                return;
+            }
+            mBlurEnabled = newEnabled;
+            notifyBlurEnabledChanged(newEnabled);
+        }
+    }
+
+    private void notifyBlurEnabledChanged(boolean enabled) {
+        int i = mBlurEnabledListeners.beginBroadcast();
+        while (i > 0) {
+            i--;
+            ICrossWindowBlurEnabledListener listener =
+                    mBlurEnabledListeners.getBroadcastItem(i);
+            try {
+                listener.onCrossWindowBlurEnabledChanged(enabled);
+            } catch (RemoteException e) {
+            }
+        }
+        mBlurEnabledListeners.finishBroadcast();
+    }
+
+
+}
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 309b5ec..62a0080 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -141,14 +141,17 @@
             mChangeListeners.get(i).onMergedOverrideConfigurationChanged(
                     mMergedOverrideConfiguration);
         }
-        dispatchConfigurationToChildren();
+        for (int i = getChildCount() - 1; i >= 0; --i) {
+            dispatchConfigurationToChild(getChildAt(i), mFullConfiguration);
+        }
     }
 
-    void dispatchConfigurationToChildren() {
-        for (int i = getChildCount() - 1; i >= 0; --i) {
-            final ConfigurationContainer child = getChildAt(i);
-            child.onConfigurationChanged(mFullConfiguration);
-        }
+    /**
+     * Dispatches the configuration to child when {@link #onConfigurationChanged(Configuration)} is
+     * called. This allows the derived classes to override how to dispatch the configuration.
+     */
+    void dispatchConfigurationToChild(E child, Configuration config) {
+        child.onConfigurationChanged(config);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 759b7fe..5ccf576 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -495,6 +495,21 @@
         return info;
     }
 
+    /**
+     * Gets the stable bounds of the DisplayArea, which is the bounds excluding insets for
+     * navigation bar, cutout, and status bar.
+     */
+    void getStableRect(Rect out) {
+        if (mDisplayContent == null) {
+            getBounds(out);
+            return;
+        }
+
+        // Intersect with the display stable bounds to get the DisplayArea stable bounds.
+        mDisplayContent.getStableRect(out);
+        out.intersect(getBounds());
+    }
+
     @Override
     public boolean providesMaxBounds() {
         return true;
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
index f505daa..a7312b3 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
@@ -67,39 +67,40 @@
  *              .setImeContainer(imeContainer)
  *              .setTaskDisplayAreas(rootTdaList);
  *
- *      // Build root hierarchy of front and rear DisplayAreaGroup.
- *      RootDisplayArea frontRoot = new RootDisplayArea(wmService, "FrontRoot", FEATURE_FRONT_ROOT);
- *      DisplayAreaPolicyBuilder.HierarchyBuilder frontGroupHierarchy =
- *          new DisplayAreaPolicyBuilder.HierarchyBuilder(frontRoot)
+ *      // Build root hierarchy of first and second DisplayAreaGroup.
+ *      RootDisplayArea firstRoot = new RootDisplayArea(wmService, "FirstRoot", FEATURE_FIRST_ROOT);
+ *      DisplayAreaPolicyBuilder.HierarchyBuilder firstGroupHierarchy =
+ *          new DisplayAreaPolicyBuilder.HierarchyBuilder(firstRoot)
  *              // (Optional) .addFeature(...)
- *              .setTaskDisplayAreas(frontTdaList);
+ *              .setTaskDisplayAreas(firstTdaList);
  *
- *      RootDisplayArea rearRoot = new RootDisplayArea(wmService, "RearRoot", FEATURE_REAR_ROOT);
- *      DisplayAreaPolicyBuilder.HierarchyBuilder rearGroupHierarchy =
- *          new DisplayAreaPolicyBuilder.HierarchyBuilder(rearRoot)
+ *      RootDisplayArea secondRoot = new RootDisplayArea(wmService, "SecondRoot",
+ *          FEATURE_REAR_ROOT);
+ *      DisplayAreaPolicyBuilder.HierarchyBuilder secondGroupHierarchy =
+ *          new DisplayAreaPolicyBuilder.HierarchyBuilder(secondRoot)
  *              // (Optional) .addFeature(...)
- *              .setTaskDisplayAreas(rearTdaList);
+ *              .setTaskDisplayAreas(secondTdaList);
  *
  *      // Define the function to select root for window to attach.
  *      BiFunction<WindowToken, Bundle, RootDisplayArea> selectRootForWindowFunc =
- *                (windowToken, bundle) -> {
- *                    if (bundle == null) {
+ *                (windowToken, options) -> {
+ *                    if (options == null) {
  *                        return root;
  *                    }
  *                    // OEMs need to define the condition.
  *                    if (...) {
- *                        return frontRoot;
+ *                        return firstRoot;
  *                    }
  *                    if (...) {
- *                        return rearRoot;
+ *                        return secondRoot;
  *                    }
  *                    return root;
  *                };
  *
  *      return new DisplayAreaPolicyBuilder()
  *                .setRootHierarchy(rootHierarchy)
- *                .addDisplayAreaGroupHierarchy(frontGroupHierarchy)
- *                .addDisplayAreaGroupHierarchy(rearGroupHierarchy)
+ *                .addDisplayAreaGroupHierarchy(firstGroupHierarchy)
+ *                .addDisplayAreaGroupHierarchy(secondGroupHierarchy)
  *                .setSelectRootForWindowFunc(selectRootForWindowFunc)
  *                .build(wmService, content);
  * </pre>
@@ -110,12 +111,12 @@
  *          - WindowedMagnification
  *              - DisplayArea.Tokens (Wallpapers can be attached here)
  *              - TaskDisplayArea
- *              - RootDisplayArea (FrontRoot)
+ *              - RootDisplayArea (FirstRoot)
  *                  - DisplayArea.Tokens (Wallpapers can be attached here)
  *                  - TaskDisplayArea
  *                  - DisplayArea.Tokens (windows above Tasks up to IME can be attached here)
  *                  - DisplayArea.Tokens (windows above IME can be attached here)
- *              - RootDisplayArea (RearRoot)
+ *              - RootDisplayArea (SecondRoot)
  *                  - DisplayArea.Tokens (Wallpapers can be attached here)
  *                  - TaskDisplayArea
  *                  - DisplayArea.Tokens (windows above Tasks up to IME can be attached here)
@@ -133,14 +134,23 @@
  * {@link RootDisplayArea}.
  */
 class DisplayAreaPolicyBuilder {
+
+    /**
+     * Key to specify the {@link RootDisplayArea} to attach the window to. Should be used by the
+     * function passed in from {@link #setSelectRootForWindowFunc(BiFunction)}
+     */
+    static final String KEY_ROOT_DISPLAY_AREA_ID = "root_display_area_id";
+
     @Nullable private HierarchyBuilder mRootHierarchyBuilder;
-    private ArrayList<HierarchyBuilder> mDisplayAreaGroupHierarchyBuilders = new ArrayList<>();
+    private final ArrayList<HierarchyBuilder> mDisplayAreaGroupHierarchyBuilders =
+            new ArrayList<>();
 
     /**
      * When a window is created, the policy will use this function, which takes window type and
      * options, to select the {@link RootDisplayArea} to place that window in. The selected root
      * can be either the one of the {@link #mRootHierarchyBuilder} or the one of any of the
      * {@link #mDisplayAreaGroupHierarchyBuilders}.
+     * @see DefaultSelectRootForWindowFunction as an example.
      **/
     @Nullable private BiFunction<Integer, Bundle, RootDisplayArea> mSelectRootForWindowFunc;
 
@@ -160,7 +170,10 @@
         return this;
     }
 
-    /** The policy will use this function to find the root to place windows in. */
+    /**
+     * The policy will use this function to find the root to place windows in.
+     * @see DefaultSelectRootForWindowFunction as an example.
+     */
     DisplayAreaPolicyBuilder setSelectRootForWindowFunc(
             BiFunction<Integer, Bundle, RootDisplayArea> selectRootForWindowFunc) {
         mSelectRootForWindowFunc = selectRootForWindowFunc;
@@ -169,7 +182,7 @@
 
     /**
      * Makes sure the setting meets the requirement:
-     * 1. {@link mRootHierarchyBuilder} must be set.
+     * 1. {@link #mRootHierarchyBuilder} must be set.
      * 2. {@link RootDisplayArea} and {@link TaskDisplayArea} must have unique ids.
      * 3. {@link Feature} below the same {@link RootDisplayArea} must have unique ids.
      * 4. There must be exactly one {@link HierarchyBuilder} that contains the IME container.
@@ -309,11 +322,57 @@
             hierarchyBuilder.build();
             displayAreaGroupRoots.add(hierarchyBuilder.mRoot);
         }
+        // Use the default function if it is not specified otherwise.
+        if (mSelectRootForWindowFunc == null) {
+            mSelectRootForWindowFunc = new DefaultSelectRootForWindowFunction(
+                    mRootHierarchyBuilder.mRoot, displayAreaGroupRoots);
+        }
         return new Result(wmService, mRootHierarchyBuilder.mRoot, displayAreaGroupRoots,
                 mSelectRootForWindowFunc);
     }
 
     /**
+     * The default function to be used for finding {@link RootDisplayArea} for window to be attached
+     * to if there is no other function set through {@link #setSelectRootForWindowFunc(BiFunction)}.
+     *
+     * When a window is created with {@link Bundle} options, this function will select the
+     * {@link RootDisplayArea} based on the options. Returns {@link #mDisplayRoot} if there is no
+     * match found.
+     */
+    private static class DefaultSelectRootForWindowFunction implements
+            BiFunction<Integer, Bundle, RootDisplayArea> {
+        final RootDisplayArea mDisplayRoot;
+        final List<RootDisplayArea> mDisplayAreaGroupRoots;
+
+        DefaultSelectRootForWindowFunction(RootDisplayArea displayRoot,
+                List<RootDisplayArea> displayAreaGroupRoots) {
+            mDisplayRoot = displayRoot;
+            mDisplayAreaGroupRoots = Collections.unmodifiableList(displayAreaGroupRoots);
+        }
+
+        @Override
+        public RootDisplayArea apply(Integer windowType, Bundle options) {
+            if (mDisplayAreaGroupRoots.isEmpty()) {
+                return mDisplayRoot;
+            }
+
+            // Select the RootDisplayArea set in options.
+            if (options != null && options.containsKey(KEY_ROOT_DISPLAY_AREA_ID)) {
+                final int rootId = options.getInt(KEY_ROOT_DISPLAY_AREA_ID);
+                if (mDisplayRoot.mFeatureId == rootId) {
+                    return mDisplayRoot;
+                }
+                for (int i = mDisplayAreaGroupRoots.size() - 1; i >= 0; i--) {
+                    if (mDisplayAreaGroupRoots.get(i).mFeatureId == rootId) {
+                        return mDisplayAreaGroupRoots.get(i);
+                    }
+                }
+            }
+            return mDisplayRoot;
+        }
+    }
+
+    /**
      *  Builder to define {@link Feature} and {@link DisplayArea} hierarchy under a
      * {@link RootDisplayArea}
      */
@@ -672,15 +731,10 @@
 
         Result(WindowManagerService wmService, RootDisplayArea root,
                 List<RootDisplayArea> displayAreaGroupRoots,
-                @Nullable BiFunction<Integer, Bundle, RootDisplayArea>
-                        selectRootForWindowFunc) {
+                BiFunction<Integer, Bundle, RootDisplayArea> selectRootForWindowFunc) {
             super(wmService, root);
             mDisplayAreaGroupRoots = Collections.unmodifiableList(displayAreaGroupRoots);
-            mSelectRootForWindowFunc = selectRootForWindowFunc == null
-                    // Always return the highest level root of the logical display when the func is
-                    // not specified.
-                    ? (type, options) -> mRoot
-                    : selectRootForWindowFunc;
+            mSelectRootForWindowFunc = selectRootForWindowFunc;
 
             // Cache the default TaskDisplayArea for quick access.
             mDefaultTaskDisplayArea = mRoot.getItemFromTaskDisplayAreas(taskDisplayArea ->
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0143e70..84bc853 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -36,6 +36,7 @@
 import static android.os.Build.VERSION_CODES.N;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.util.DisplayMetrics.DENSITY_DEFAULT;
+import static android.util.RotationUtils.deltaRotation;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
 import static android.view.Display.FLAG_PRIVATE;
@@ -47,7 +48,6 @@
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.ITYPE_RIGHT_GESTURES;
 import static android.view.Surface.ROTATION_0;
-import static android.view.Surface.ROTATION_180;
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
 import static android.view.View.GONE;
@@ -150,7 +150,6 @@
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
-import android.app.WindowConfiguration;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ActivityInfo.ScreenOrientation;
@@ -158,10 +157,8 @@
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.Insets;
-import android.graphics.Matrix;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.graphics.RectF;
 import android.graphics.Region;
 import android.graphics.Region.Op;
 import android.hardware.HardwareBuffer;
@@ -206,6 +203,7 @@
 import android.view.RemoteAnimationDefinition;
 import android.view.RoundedCorners;
 import android.view.Surface;
+import android.view.Surface.Rotation;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
 import android.view.SurfaceSession;
@@ -449,8 +447,6 @@
     /** Save allocating when calculating rects */
     private final Rect mTmpRect = new Rect();
     private final Rect mTmpRect2 = new Rect();
-    private final RectF mTmpRectF = new RectF();
-    private final Matrix mTmpMatrix = new Matrix();
     private final Region mTmpRegion = new Region();
 
     /** Used for handing back size of display */
@@ -461,8 +457,8 @@
     /** Remove this display when animation on it has completed. */
     private boolean mDeferredRemoval;
 
-    final DockedStackDividerController mDividerControllerLocked;
-    final PinnedStackController mPinnedStackControllerLocked;
+    final DockedTaskDividerController mDividerControllerLocked;
+    final PinnedTaskController mPinnedTaskControllerLocked;
 
     final ArrayList<WindowState> mTapExcludedWindows = new ArrayList<>();
     /** A collection of windows that provide tap exclude regions inside of them. */
@@ -1012,8 +1008,8 @@
             mDisplayPolicy.systemReady();
         }
         mWindowCornerRadius = mDisplayPolicy.getWindowCornerRadius();
-        mDividerControllerLocked = new DockedStackDividerController(this);
-        mPinnedStackControllerLocked = new PinnedStackController(mWmService, this);
+        mDividerControllerLocked = new DockedTaskDividerController(this);
+        mPinnedTaskControllerLocked = new PinnedTaskController(mWmService, this);
 
         final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(mSession)
                 .setOpaque(true)
@@ -1289,7 +1285,7 @@
         return mInsetsPolicy;
     }
 
-    @Surface.Rotation
+    @Rotation
     int getRotation() {
         return mDisplayRotation.getRotation();
     }
@@ -1479,7 +1475,7 @@
      * Returns a valid rotation if the activity can use different orientation than the display.
      * Otherwise {@link #ROTATION_UNDEFINED}.
      */
-    @Surface.Rotation
+    @Rotation
     int rotationForActivityInDifferentOrientation(@NonNull ActivityRecord r) {
         if (!WindowManagerService.ENABLE_FIXED_ROTATION_TRANSFORM) {
             return ROTATION_UNDEFINED;
@@ -1567,7 +1563,7 @@
             // has it own policy for bounds, the activity bounds based on parent is unknown.
             return false;
         }
-        if (mPinnedStackControllerLocked.isPipActiveOrWindowingModeChanging()) {
+        if (mPinnedTaskControllerLocked.isPipActiveOrWindowingModeChanging()) {
             // Use normal rotation animation because seamless PiP rotation is not supported yet.
             return false;
         }
@@ -1614,7 +1610,7 @@
      * Sets the provided record to {@link #mFixedRotationLaunchingApp} if possible to apply fixed
      * rotation transform to it and indicate that the display may be rotated after it is launched.
      */
-    void setFixedRotationLaunchingApp(@NonNull ActivityRecord r, @Surface.Rotation int rotation) {
+    void setFixedRotationLaunchingApp(@NonNull ActivityRecord r, @Rotation int rotation) {
         final WindowToken prevRotatedLaunchingApp = mFixedRotationLaunchingApp;
         if (prevRotatedLaunchingApp == r
                 && r.getWindowConfiguration().getRotation() == rotation) {
@@ -2296,12 +2292,12 @@
         }
     }
 
-    DockedStackDividerController getDockedDividerController() {
+    DockedTaskDividerController getDockedDividerController() {
         return mDividerControllerLocked;
     }
 
-    PinnedStackController getPinnedStackController() {
-        return mPinnedStackControllerLocked;
+    PinnedTaskController getPinnedTaskController() {
+        return mPinnedTaskControllerLocked;
     }
 
     /**
@@ -2382,10 +2378,10 @@
      * for bounds calculations.
      */
     void preOnConfigurationChanged() {
-        final PinnedStackController pinnedStackController = getPinnedStackController();
+        final PinnedTaskController pinnedTaskController = getPinnedTaskController();
 
-        if (pinnedStackController != null) {
-            getPinnedStackController().onConfigurationChanged();
+        if (pinnedTaskController != null) {
+            getPinnedTaskController().onConfigurationChanged();
         }
     }
 
@@ -2681,6 +2677,7 @@
         mWmService.mDisplayWindowSettings.setForcedSize(this, width, height);
     }
 
+    @Override
     void getStableRect(Rect out) {
         final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState();
         out.set(state.getDisplayFrame());
@@ -2929,7 +2926,7 @@
         final boolean imeVisible = imeWin != null && imeWin.isVisible()
                 && imeWin.isDisplayed();
         final int imeHeight = getInputMethodWindowVisibleHeight();
-        mPinnedStackControllerLocked.setAdjustedForIme(imeVisible, imeHeight);
+        mPinnedTaskControllerLocked.setAdjustedForIme(imeVisible, imeHeight);
     }
 
     int getInputMethodWindowVisibleHeight() {
@@ -2947,31 +2944,10 @@
         return dockFrame.bottom - imeFrame.top;
     }
 
-    void prepareFreezingTaskBounds() {
-        forAllRootTasks(Task::prepareFreezingTaskBounds);
-    }
-
-    void rotateBounds(int oldRotation, int newRotation, Rect bounds) {
-        getBounds(mTmpRect, newRotation);
-        rotateBounds(mTmpRect, oldRotation, newRotation, bounds);
-    }
-
-    void rotateBounds(Rect parentBounds, int oldRotation, int newRotation, Rect bounds) {
-        // Compute a transform matrix to undo the coordinate space transformation,
-        // and present the window at the same physical position it previously occupied.
-        final int deltaRotation = deltaRotation(newRotation, oldRotation);
-        createRotationMatrix(
-                deltaRotation, parentBounds.width(), parentBounds.height(), mTmpMatrix);
-
-        mTmpRectF.set(bounds);
-        mTmpMatrix.mapRect(mTmpRectF);
-        mTmpRectF.round(bounds);
-    }
-
-    static int deltaRotation(int oldRotation, int newRotation) {
-        int delta = newRotation - oldRotation;
-        if (delta < 0) delta += 4;
-        return delta;
+    void rotateBounds(@Rotation int oldRotation, @Rotation int newRotation, Rect inOutBounds) {
+        // Get display bounds on oldRotation as parent bounds for the rotation.
+        getBounds(mTmpRect, oldRotation);
+        RotationUtils.rotateBounds(inOutBounds, mTmpRect, oldRotation, newRotation);
     }
 
     public void setRotationAnimation(ScreenRotationAnimation screenRotationAnimation) {
@@ -2985,35 +2961,6 @@
         return mScreenRotationAnimation;
     }
 
-    private static void createRotationMatrix(int rotation, float displayWidth, float displayHeight,
-            Matrix outMatrix) {
-        // For rotations without Z-ordering we don't need the target rectangle's position.
-        createRotationMatrix(rotation, 0 /* rectLeft */, 0 /* rectTop */, displayWidth,
-                displayHeight, outMatrix);
-    }
-
-    static void createRotationMatrix(int rotation, float rectLeft, float rectTop,
-            float displayWidth, float displayHeight, Matrix outMatrix) {
-        switch (rotation) {
-            case ROTATION_0:
-                outMatrix.reset();
-                break;
-            case ROTATION_270:
-                outMatrix.setRotate(270, 0, 0);
-                outMatrix.postTranslate(0, displayHeight);
-                outMatrix.postTranslate(rectTop, 0);
-                break;
-            case ROTATION_180:
-                outMatrix.reset();
-                break;
-            case ROTATION_90:
-                outMatrix.setRotate(90, 0, 0);
-                outMatrix.postTranslate(displayWidth, 0);
-                outMatrix.postTranslate(-rectTop, rectLeft);
-                break;
-        }
-    }
-
     @Override
     public void dumpDebug(ProtoOutputStream proto, long fieldId,
             @WindowTraceLogLevel int logLevel) {
@@ -3200,7 +3147,7 @@
         }
 
         pw.println();
-        mPinnedStackControllerLocked.dump(prefix, pw);
+        mPinnedTaskControllerLocked.dump(prefix, pw);
 
         pw.println();
         mDisplayFrames.dump(prefix, pw);
@@ -3639,8 +3586,7 @@
     }
 
     private boolean isImeControlledByApp() {
-        return mImeInputTarget != null && !WindowConfiguration.isSplitScreenWindowingMode(
-                        mImeInputTarget.getWindowingMode());
+        return mImeInputTarget != null && !mImeInputTarget.inMultiWindowMode();
     }
 
     boolean isImeAttachedToApp() {
@@ -3754,8 +3700,8 @@
         // app.
         assignWindowLayers(true /* setLayoutNeeded */);
         // 3. The z-order of IME might have been changed. Update the above insets state.
-        mInsetsStateController.updateAboveInsetsState(
-                mInputMethodWindow, true /* notifyInsetsChange */);
+        mInsetsStateController.updateAboveInsetsState(mInputMethodWindow,
+                mInsetsStateController.getRawInsetsState().getSourceOrDefaultVisibility(ITYPE_IME));
         // 4. Update the IME control target to apply any inset change and animation.
         // 5. Reparent the IME container surface to either the input target app, or the IME window
         // parent.
@@ -4156,13 +4102,6 @@
      */
     void onWindowAnimationFinished(@NonNull WindowContainer wc, int type) {
         if (type == ANIMATION_TYPE_APP_TRANSITION || type == ANIMATION_TYPE_RECENTS) {
-            // Unfreeze the insets state of the frozen target when the animation finished if exists.
-            final Task task = wc.asTask();
-            if (task != null) {
-                task.forAllWindows(w -> {
-                    w.clearFrozenInsetsState();
-                }, true /* traverseTopToBottom */);
-            }
             removeImeSurfaceImmediately();
         }
     }
@@ -4289,17 +4228,14 @@
         out.set(left, top, left + width, top + height);
     }
 
-    private void getBounds(Rect out, int orientation) {
+    private void getBounds(Rect out, @Rotation int rotation) {
         getBounds(out);
 
         // Rotate the Rect if needed.
         final int currentRotation = mDisplayInfo.rotation;
-        final int rotationDelta = deltaRotation(currentRotation, orientation);
+        final int rotationDelta = deltaRotation(currentRotation, rotation);
         if (rotationDelta == ROTATION_90 || rotationDelta == ROTATION_270) {
-            createRotationMatrix(rotationDelta, mBaseDisplayWidth, mBaseDisplayHeight, mTmpMatrix);
-            mTmpRectF.set(out);
-            mTmpMatrix.mapRect(mTmpRectF);
-            mTmpRectF.round(out);
+            out.set(0, 0, out.height(), out.width());
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 5460e36..af9cdeb 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -24,6 +24,8 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.content.res.Configuration.UI_MODE_TYPE_CAR;
 import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
+import static android.util.RotationUtils.deltaRotation;
+import static android.util.RotationUtils.rotateBounds;
 import static android.view.Display.TYPE_INTERNAL;
 import static android.view.InsetsState.ITYPE_BOTTOM_MANDATORY_GESTURES;
 import static android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
@@ -67,6 +69,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
 import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
+import static android.view.WindowManager.LayoutParams.TYPE_POINTER;
 import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
@@ -240,7 +243,7 @@
         }
     }
 
-    private final SystemGesturesPointerEventListener mSystemGestures;
+    private SystemGesturesPointerEventListener mSystemGestures;
 
     private volatile int mLidState = LID_ABSENT;
     private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
@@ -382,7 +385,7 @@
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
 
-    private final GestureNavigationSettingsObserver mGestureNavigationSettingsObserver;
+    private GestureNavigationSettingsObserver mGestureNavigationSettingsObserver;
 
     private final WindowManagerInternal.AppTransitionListener mAppTransitionListener;
 
@@ -446,119 +449,6 @@
 
         final Looper looper = UiThread.getHandler().getLooper();
         mHandler = new PolicyHandler(looper);
-        mSystemGestures = new SystemGesturesPointerEventListener(mContext, mHandler,
-                new SystemGesturesPointerEventListener.Callbacks() {
-                    @Override
-                    public void onSwipeFromTop() {
-                        synchronized (mLock) {
-                            if (mStatusBar != null) {
-                                requestTransientBars(mStatusBar);
-                            }
-                            checkAltBarSwipeForTransientBars(ALT_BAR_TOP);
-                        }
-                    }
-
-                    @Override
-                    public void onSwipeFromBottom() {
-                        synchronized (mLock) {
-                            if (mNavigationBar != null
-                                    && mNavigationBarPosition == NAV_BAR_BOTTOM) {
-                                requestTransientBars(mNavigationBar);
-                            }
-                            checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM);
-                        }
-                    }
-
-                    @Override
-                    public void onSwipeFromRight() {
-                        final Region excludedRegion = Region.obtain();
-                        synchronized (mLock) {
-                            mDisplayContent.calculateSystemGestureExclusion(
-                                    excludedRegion, null /* outUnrestricted */);
-                            final boolean excluded =
-                                    mSystemGestures.currentGestureStartedInRegion(excludedRegion);
-                            if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_RIGHT
-                                    || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
-                                requestTransientBars(mNavigationBar);
-                            }
-                            checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT);
-                        }
-                        excludedRegion.recycle();
-                    }
-
-                    @Override
-                    public void onSwipeFromLeft() {
-                        final Region excludedRegion = Region.obtain();
-                        synchronized (mLock) {
-                            mDisplayContent.calculateSystemGestureExclusion(
-                                    excludedRegion, null /* outUnrestricted */);
-                            final boolean excluded =
-                                    mSystemGestures.currentGestureStartedInRegion(excludedRegion);
-                            if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_LEFT
-                                    || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
-                                requestTransientBars(mNavigationBar);
-                            }
-                            checkAltBarSwipeForTransientBars(ALT_BAR_LEFT);
-                        }
-                        excludedRegion.recycle();
-                    }
-
-                    @Override
-                    public void onFling(int duration) {
-                        if (mService.mPowerManagerInternal != null) {
-                            mService.mPowerManagerInternal.setPowerBoost(
-                                    Boost.INTERACTION, duration);
-                        }
-                    }
-
-                    @Override
-                    public void onDebug() {
-                        // no-op
-                    }
-
-                    private WindowOrientationListener getOrientationListener() {
-                        final DisplayRotation rotation = mDisplayContent.getDisplayRotation();
-                        return rotation != null ? rotation.getOrientationListener() : null;
-                    }
-
-                    @Override
-                    public void onDown() {
-                        final WindowOrientationListener listener = getOrientationListener();
-                        if (listener != null) {
-                            listener.onTouchStart();
-                        }
-                    }
-
-                    @Override
-                    public void onUpOrCancel() {
-                        final WindowOrientationListener listener = getOrientationListener();
-                        if (listener != null) {
-                            listener.onTouchEnd();
-                        }
-                    }
-
-                    @Override
-                    public void onMouseHoverAtTop() {
-                        mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
-                        Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
-                        msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
-                        mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
-                    }
-
-                    @Override
-                    public void onMouseHoverAtBottom() {
-                        mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
-                        Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
-                        msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
-                        mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
-                    }
-
-                    @Override
-                    public void onMouseLeaveFromEdge() {
-                        mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
-                    }
-                });
-        displayContent.registerPointerEventListener(mSystemGestures);
         mAppTransitionListener = new WindowManagerInternal.AppTransitionListener() {
 
             private Runnable mAppTransitionPending = () -> {
@@ -614,7 +504,7 @@
         mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper,
                 mService.mVrModeEnabled);
 
-        // TODO: Make it can take screenshot on external display
+        // TODO(b/180986447): Make it can take screenshot on external display
         mScreenshotHelper = displayContent.isDefaultDisplay
                 ? new ScreenshotHelper(mContext) : null;
 
@@ -638,16 +528,6 @@
         mRefreshRatePolicy = new RefreshRatePolicy(mService,
                 mDisplayContent.getDisplayInfo(),
                 mService.mHighRefreshRateDenylist);
-
-        mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(mHandler,
-                mContext, () -> {
-            synchronized (mLock) {
-                onConfigurationChanged();
-                mSystemGestures.onConfigurationChanged();
-                mDisplayContent.updateSystemGestureExclusion();
-            }
-        });
-        mHandler.post(mGestureNavigationSettingsObserver::register);
     }
 
     private void checkAltBarSwipeForTransientBars(@WindowManagerPolicy.AltBarPosition int pos) {
@@ -666,12 +546,154 @@
     }
 
     void systemReady() {
-        mSystemGestures.systemReady();
         if (mService.mPointerLocationEnabled) {
             setPointerLocationEnabled(true);
         }
     }
 
+    @NonNull
+    private GestureNavigationSettingsObserver getGestureNavigationSettingsObserver() {
+        if (mGestureNavigationSettingsObserver == null) {
+            mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(mHandler,
+                    mContext, () -> {
+                synchronized (mLock) {
+                    onConfigurationChanged();
+                    getSystemGestures().onConfigurationChanged();
+                    mDisplayContent.updateSystemGestureExclusion();
+                }
+            });
+            mHandler.post(mGestureNavigationSettingsObserver::register);
+        }
+        return mGestureNavigationSettingsObserver;
+    }
+
+    @NonNull
+    private SystemGesturesPointerEventListener getSystemGestures() {
+        if (mSystemGestures == null) {
+            final Context gestureContext = mUiContext.createWindowContext(
+                    mDisplayContent.getDisplay(), TYPE_POINTER, null /* options */);
+            mSystemGestures = new SystemGesturesPointerEventListener(gestureContext, mHandler,
+                    new SystemGesturesPointerEventListener.Callbacks() {
+                        @Override
+                        public void onSwipeFromTop() {
+                            synchronized (mLock) {
+                                if (mStatusBar != null) {
+                                    requestTransientBars(mStatusBar);
+                                }
+                                checkAltBarSwipeForTransientBars(ALT_BAR_TOP);
+                            }
+                        }
+
+                        @Override
+                        public void onSwipeFromBottom() {
+                            synchronized (mLock) {
+                                if (mNavigationBar != null
+                                        && mNavigationBarPosition == NAV_BAR_BOTTOM) {
+                                    requestTransientBars(mNavigationBar);
+                                }
+                                checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM);
+                            }
+                        }
+
+                        @Override
+                        public void onSwipeFromRight() {
+                            final Region excludedRegion = Region.obtain();
+                            synchronized (mLock) {
+                                mDisplayContent.calculateSystemGestureExclusion(
+                                        excludedRegion, null /* outUnrestricted */);
+                                final boolean excluded = mSystemGestures
+                                        .currentGestureStartedInRegion(excludedRegion);
+                                if (mNavigationBar != null
+                                        && (mNavigationBarPosition == NAV_BAR_RIGHT
+                                        || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
+                                    requestTransientBars(mNavigationBar);
+                                }
+                                checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT);
+                            }
+                            excludedRegion.recycle();
+                        }
+
+                        @Override
+                        public void onSwipeFromLeft() {
+                            final Region excludedRegion = Region.obtain();
+                            synchronized (mLock) {
+                                mDisplayContent.calculateSystemGestureExclusion(
+                                        excludedRegion, null /* outUnrestricted */);
+                                final boolean excluded = mSystemGestures
+                                        .currentGestureStartedInRegion(excludedRegion);
+                                if (mNavigationBar != null
+                                        && (mNavigationBarPosition == NAV_BAR_LEFT
+                                        || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
+                                    requestTransientBars(mNavigationBar);
+                                }
+                                checkAltBarSwipeForTransientBars(ALT_BAR_LEFT);
+                            }
+                            excludedRegion.recycle();
+                        }
+
+                        @Override
+                        public void onFling(int duration) {
+                            if (mService.mPowerManagerInternal != null) {
+                                mService.mPowerManagerInternal.setPowerBoost(
+                                        Boost.INTERACTION, duration);
+                            }
+                        }
+
+                        @Override
+                        public void onDebug() {
+                            // no-op
+                        }
+
+                        private WindowOrientationListener getOrientationListener() {
+                            final DisplayRotation rotation = mDisplayContent.getDisplayRotation();
+                            return rotation != null ? rotation.getOrientationListener() : null;
+                        }
+
+                        @Override
+                        public void onDown() {
+                            final WindowOrientationListener listener = getOrientationListener();
+                            if (listener != null) {
+                                listener.onTouchStart();
+                            }
+                        }
+
+                        @Override
+                        public void onUpOrCancel() {
+                            final WindowOrientationListener listener = getOrientationListener();
+                            if (listener != null) {
+                                listener.onTouchEnd();
+                            }
+                        }
+
+                        @Override
+                        public void onMouseHoverAtTop() {
+                            mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
+                            Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
+                            msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
+                            mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
+                        }
+
+                        @Override
+                        public void onMouseHoverAtBottom() {
+                            mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
+                            Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
+                            msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
+                            mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
+                        }
+
+                        @Override
+                        public void onMouseLeaveFromEdge() {
+                            mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
+                        }
+                    });
+            mDisplayContent.registerPointerEventListener(getSystemGestures());
+            if (mService.mSystemReady) {
+                mSystemGestures.systemReady();
+            }
+        }
+        return mSystemGestures;
+    }
+
     private int getDisplayId() {
         return mDisplayContent.getDisplayId();
     }
@@ -1046,11 +1068,17 @@
             return;
         }
 
-        // Get displayFrames bounds
-        sTmpDisplayFrameBounds.set(0, 0, displayFrames.mDisplayWidth, displayFrames.mDisplayHeight);
+        // Get displayFrames bounds as it is on WindowState's rotation.
+        final int deltaRotation = deltaRotation(windowRotation, displayFrames.mRotation);
+        if (deltaRotation == Surface.ROTATION_90 || deltaRotation == Surface.ROTATION_270) {
+            sTmpDisplayFrameBounds.set(
+                    0, 0, displayFrames.mDisplayHeight, displayFrames.mDisplayWidth);
+        } else {
+            sTmpDisplayFrameBounds.set(
+                    0, 0, displayFrames.mDisplayWidth, displayFrames.mDisplayHeight);
+        }
         // Rotate the WindowState's bounds based on the displayFrames rotation
-        mDisplayContent.rotateBounds(sTmpDisplayFrameBounds, windowRotation,
-                displayFrames.mRotation, outBounds);
+        rotateBounds(outBounds, sTmpDisplayFrameBounds, deltaRotation);
     }
 
     /**
@@ -1447,8 +1475,7 @@
     }
 
     void onDisplayInfoChanged(DisplayInfo info) {
-        mSystemGestures.screenWidth = info.logicalWidth;
-        mSystemGestures.screenHeight = info.logicalHeight;
+        getSystemGestures().onDisplayInfoChanged(info);
     }
 
     private void layoutStatusBar(DisplayFrames displayFrames, Rect contentFrame) {
@@ -1961,7 +1988,7 @@
     public void onOverlayChangedLw() {
         updateCurrentUserResources();
         onConfigurationChanged();
-        mSystemGestures.onConfigurationChanged();
+        getSystemGestures().onConfigurationChanged();
     }
 
     /**
@@ -2032,10 +2059,10 @@
         }
 
         mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode);
-        mLeftGestureInset = mGestureNavigationSettingsObserver.getLeftSensitivity(res);
-        mRightGestureInset = mGestureNavigationSettingsObserver.getRightSensitivity(res);
-        mNavButtonForcedVisible =
-                mGestureNavigationSettingsObserver.areNavigationButtonForcedVisible();
+        final GestureNavigationSettingsObserver observer = getGestureNavigationSettingsObserver();
+        mLeftGestureInset = observer.getLeftSensitivity(res);
+        mRightGestureInset = observer.getRightSensitivity(res);
+        mNavButtonForcedVisible = observer.areNavigationButtonForcedVisible();
         mNavigationBarLetsThroughTaps = res.getBoolean(R.bool.config_navBarTapThrough);
         mNavigationBarAlwaysShowOnSideGesture =
                 res.getBoolean(R.bool.config_navBarAlwaysShowOnSideEdgeGesture);
@@ -2678,8 +2705,9 @@
         boolean newImmersiveMode = isImmersiveMode(win);
         if (oldImmersiveMode != newImmersiveMode) {
             mLastImmersiveMode = newImmersiveMode;
-            final String pkg = win.getOwningPackage();
-            mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,
+            // The immersive confirmation window should be attached to the immersive window root.
+            final int rootDisplayAreaId = win.getRootDisplayArea().mFeatureId;
+            mImmersiveModeConfirmation.immersiveModeChangedLw(rootDisplayAreaId, newImmersiveMode,
                     mService.mPolicy.isUserSetupComplete(),
                     isNavBarEmpty(disableFlags));
         }
@@ -3047,7 +3075,7 @@
     }
 
     void release() {
-        mHandler.post(mGestureNavigationSettingsObserver::unregister);
+        mHandler.post(getGestureNavigationSettingsObserver()::unregister);
     }
 
     @VisibleForTesting
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index d5ded97..63cb38a 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.util.RotationUtils.deltaRotation;
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
@@ -475,7 +476,7 @@
                 "Display id=%d rotation changed to %d from %d, lastOrientation=%d",
                         displayId, rotation, oldRotation, lastOrientation);
 
-        if (DisplayContent.deltaRotation(rotation, oldRotation) != 2) {
+        if (deltaRotation(oldRotation, rotation) != Surface.ROTATION_180) {
             mDisplayContent.mWaitingForConfig = true;
         }
 
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedTaskDividerController.java
similarity index 89%
rename from services/core/java/com/android/server/wm/DockedStackDividerController.java
rename to services/core/java/com/android/server/wm/DockedTaskDividerController.java
index de4bdaa..fb9d064 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedTaskDividerController.java
@@ -19,16 +19,16 @@
 import android.graphics.Rect;
 
 /**
- * Keeps information about the docked stack divider.
+ * Keeps information about the docked task divider.
  */
-public class DockedStackDividerController {
+public class DockedTaskDividerController {
 
     private final DisplayContent mDisplayContent;
     private boolean mResizing;
 
     private final Rect mTouchRegion = new Rect();
 
-    DockedStackDividerController(DisplayContent displayContent) {
+    DockedTaskDividerController(DisplayContent displayContent) {
         mDisplayContent = displayContent;
     }
 
@@ -58,6 +58,6 @@
 
     private void resetDragResizingChangeReported() {
         mDisplayContent.forAllWindows(WindowState::resetDragResizingChangeReported,
-                true /* traverseTopToBottom */ );
+                true /* traverseTopToBottom */);
     }
 }
diff --git a/services/core/java/com/android/server/wm/FactoryErrorDialog.java b/services/core/java/com/android/server/wm/FactoryErrorDialog.java
index 88b5475..afdf1ee 100644
--- a/services/core/java/com/android/server/wm/FactoryErrorDialog.java
+++ b/services/core/java/com/android/server/wm/FactoryErrorDialog.java
@@ -41,6 +41,11 @@
     public void onStop() {
     }
 
+    @Override
+    protected void closeDialog() {
+        /* Do nothing */
+    }
+
     private final Handler mHandler = new Handler() {
         public void handleMessage(Message msg) {
             throw new RuntimeException("Rebooting from failed factory test");
diff --git a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
index 9286a46..567b6c2 100644
--- a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
@@ -19,9 +19,11 @@
 import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
 
 import android.animation.ArgbEvaluator;
 import android.animation.ValueAnimator;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.content.BroadcastReceiver;
@@ -32,10 +34,12 @@
 import android.graphics.PixelFormat;
 import android.graphics.drawable.ColorDrawable;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -43,6 +47,7 @@
 import android.util.Slog;
 import android.view.Display;
 import android.view.Gravity;
+import android.view.IWindowManager;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
@@ -50,6 +55,7 @@
 import android.view.WindowInsets;
 import android.view.WindowInsets.Type;
 import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
@@ -67,6 +73,8 @@
     private static final boolean DEBUG = false;
     private static final boolean DEBUG_SHOW_EVERY_TIME = false; // super annoying, use with caution
     private static final String CONFIRMED = "confirmed";
+    private static final int IMMERSIVE_MODE_CONFIRMATION_WINDOW_TYPE =
+            WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
 
     private static boolean sConfirmed;
 
@@ -78,7 +86,15 @@
 
     private ClingWindowView mClingWindow;
     private long mPanicTime;
+    /** The last {@link WindowManager} that is used to add the confirmation window. */
+    @Nullable
     private WindowManager mWindowManager;
+    /**
+     * The WindowContext that is registered with {@link #mWindowManager} with options to specify the
+     * {@link RootDisplayArea} to attach the confirmation window.
+     */
+    @Nullable
+    private Context mWindowContext;
     // Local copy of vr mode enabled state, to avoid calling into VrManager with
     // the lock held.
     private boolean mVrModeEnabled;
@@ -132,7 +148,7 @@
         }
     }
 
-    void immersiveModeChangedLw(String pkg, boolean isImmersiveMode,
+    void immersiveModeChangedLw(int rootDisplayAreaId, boolean isImmersiveMode,
             boolean userSetupComplete, boolean navBarEmpty) {
         mHandler.removeMessages(H.SHOW);
         if (isImmersiveMode) {
@@ -143,7 +159,9 @@
                     && !navBarEmpty
                     && !UserManager.isDeviceInDemoMode(mContext)
                     && (mLockTaskState != LOCK_TASK_MODE_LOCKED)) {
-                mHandler.sendEmptyMessageDelayed(H.SHOW, mShowDelayMs);
+                final Message msg = mHandler.obtainMessage(H.SHOW);
+                msg.arg1 = rootDisplayAreaId;
+                mHandler.sendMessageDelayed(msg, mShowDelayMs);
             }
         } else {
             mHandler.sendEmptyMessage(H.HIDE);
@@ -175,7 +193,8 @@
     private void handleHide() {
         if (mClingWindow != null) {
             if (DEBUG) Slog.d(TAG, "Hiding immersive mode confirmation");
-            getWindowManager().removeView(mClingWindow);
+            // We don't care which root display area the window manager is specifying for removal.
+            getWindowManager(FEATURE_UNDEFINED).removeView(mClingWindow);
             mClingWindow = null;
         }
     }
@@ -184,7 +203,7 @@
         final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
                 ViewGroup.LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL,
+                IMMERSIVE_MODE_CONFIRMATION_WINDOW_TYPE,
                 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                         | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
                         | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
@@ -353,23 +372,57 @@
      * DO HOLD THE WINDOW MANAGER LOCK WHEN CALLING THIS METHOD
      * The reason why we add this method is to avoid the deadlock of WMG->WMS and WMS->WMG
      * when ImmersiveModeConfirmation object is created.
+     *
+     * @return the WindowManager specifying with the {@code rootDisplayAreaId} to attach the
+     *         confirmation window.
      */
-    private WindowManager getWindowManager() {
-        if (mWindowManager == null) {
-            mWindowManager = (WindowManager)
-                      mContext.getSystemService(Context.WINDOW_SERVICE);
+    private WindowManager getWindowManager(int rootDisplayAreaId) {
+        if (mWindowManager == null || mWindowContext == null) {
+            // Create window context to specify the RootDisplayArea
+            final Bundle options = getOptionsForWindowContext(rootDisplayAreaId);
+            mWindowContext = mContext.createWindowContext(
+                    IMMERSIVE_MODE_CONFIRMATION_WINDOW_TYPE, options);
+            mWindowManager = mWindowContext.getSystemService(WindowManager.class);
+            return mWindowManager;
         }
+
+        // Update the window context and window manager to specify the RootDisplayArea
+        final Bundle options = getOptionsForWindowContext(rootDisplayAreaId);
+        final IWindowManager wms = WindowManagerGlobal.getWindowManagerService();
+        try {
+            wms.registerWindowContextListener(mWindowContext.getWindowContextToken(),
+                    IMMERSIVE_MODE_CONFIRMATION_WINDOW_TYPE, mContext.getDisplayId(), options);
+        }  catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+
         return mWindowManager;
     }
 
-    private void handleShow() {
+    /**
+     * Returns options that specify the {@link RootDisplayArea} to attach the confirmation window.
+     *         {@code null} if the {@code rootDisplayAreaId} is {@link FEATURE_UNDEFINED}.
+     */
+    @Nullable
+    private Bundle getOptionsForWindowContext(int rootDisplayAreaId) {
+        // In case we don't care which root display area the window manager is specifying.
+        if (rootDisplayAreaId == FEATURE_UNDEFINED) {
+            return null;
+        }
+
+        final Bundle options = new Bundle();
+        options.putInt(DisplayAreaPolicyBuilder.KEY_ROOT_DISPLAY_AREA_ID, rootDisplayAreaId);
+        return options;
+    }
+
+    private void handleShow(int rootDisplayAreaId) {
         if (DEBUG) Slog.d(TAG, "Showing immersive mode confirmation");
 
         mClingWindow = new ClingWindowView(mContext, mConfirm);
 
         // show the confirmation
         WindowManager.LayoutParams lp = getClingWindowLayoutParams();
-        getWindowManager().addView(mClingWindow, lp);
+        getWindowManager(rootDisplayAreaId).addView(mClingWindow, lp);
     }
 
     private final Runnable mConfirm = new Runnable() {
@@ -396,7 +449,7 @@
         public void handleMessage(Message msg) {
             switch(msg.what) {
                 case SHOW:
-                    handleShow();
+                    handleShow(msg.arg1);
                     break;
                 case HIDE:
                     handleHide();
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 75176df..a971794 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -124,7 +124,8 @@
                 ? provider.getSource().getType() : ITYPE_INVALID;
         return getInsetsForTarget(type, target.getWindowingMode(), target.isAlwaysOnTop(),
                 target.getFrozenInsetsState() != null ? target.getFrozenInsetsState() :
-                target.mAboveInsetsState);
+                        (target.mAttrs.receiveInsetsIgnoringZOrder ? mState :
+                         target.mAboveInsetsState));
     }
 
     InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) {
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index e18516d..62c155a 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -540,7 +540,7 @@
             setStatusBarState(mLockTaskModeState, userId);
             setKeyguardState(mLockTaskModeState, userId);
             if (oldLockTaskModeState == LOCK_TASK_MODE_PINNED) {
-                lockKeyguardIfNeeded();
+                lockKeyguardIfNeeded(userId);
             }
             if (getDevicePolicyManager() != null) {
                 getDevicePolicyManager().notifyLockTaskModeChanged(false, null, userId);
@@ -886,15 +886,15 @@
      * Helper method for locking the device immediately. This may be necessary when the device
      * leaves the pinned mode.
      */
-    private void lockKeyguardIfNeeded() {
-        if (shouldLockKeyguard()) {
+    private void lockKeyguardIfNeeded(int userId) {
+        if (shouldLockKeyguard(userId)) {
             mWindowManager.lockNow(null);
             mWindowManager.dismissKeyguard(null /* callback */, null /* message */);
             getLockPatternUtils().requireCredentialEntry(USER_ALL);
         }
     }
 
-    private boolean shouldLockKeyguard() {
+    private boolean shouldLockKeyguard(int userId) {
         // This functionality should be kept consistent with
         // com.android.settings.security.ScreenPinningSettings (see b/127605586)
         try {
@@ -904,7 +904,7 @@
         } catch (Settings.SettingNotFoundException e) {
             // Log to SafetyNet for b/127605586
             android.util.EventLog.writeEvent(0x534e4554, "127605586", -1, "");
-            return getLockPatternUtils().isSecure(USER_CURRENT);
+            return getLockPatternUtils().isSecure(userId);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedTaskController.java
similarity index 79%
rename from services/core/java/com/android/server/wm/PinnedStackController.java
rename to services/core/java/com/android/server/wm/PinnedTaskController.java
index 8fe2481..15e078b 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedTaskController.java
@@ -29,18 +29,18 @@
 import android.util.Log;
 import android.util.Slog;
 import android.view.DisplayInfo;
-import android.view.IPinnedStackListener;
+import android.view.IPinnedTaskListener;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 
 /**
- * Holds the common state of the pinned stack between the system and SystemUI. If SystemUI ever
+ * Holds the common state of the pinned task between the system and SystemUI. If SystemUI ever
  * needs to be restarted, it will be notified with the last known state.
  *
- * Changes to the pinned stack also flow through this controller, and generally, the system only
- * changes the pinned stack bounds through this controller in two ways:
+ * Changes to the pinned task also flow through this controller, and generally, the system only
+ * changes the pinned task bounds through this controller in two ways:
  *
  * 1) When first entering PiP: the controller returns the valid bounds given, taking aspect ratio
  *    and IME state into account.
@@ -49,18 +49,18 @@
  *    SystemUI adjustments (ie. expanded for menu, interaction, etc).
  *
  * Other changes in the system, including adjustment of IME, configuration change, and more are
- * handled by SystemUI (similar to the docked stack divider).
+ * handled by SystemUI (similar to the docked task divider).
  */
-class PinnedStackController {
+class PinnedTaskController {
 
-    private static final String TAG = TAG_WITH_CLASS_NAME ? "PinnedStackController" : TAG_WM;
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "PinnedTaskController" : TAG_WM;
 
     private final WindowManagerService mService;
     private final DisplayContent mDisplayContent;
 
-    private IPinnedStackListener mPinnedStackListener;
-    private final PinnedStackListenerDeathHandler mPinnedStackListenerDeathHandler =
-            new PinnedStackListenerDeathHandler();
+    private IPinnedTaskListener mPinnedTaskListener;
+    private final PinnedTaskListenerDeathHandler mPinnedTaskListenerDeathHandler =
+            new PinnedTaskListenerDeathHandler();
 
     /** Whether the PiP is entering or leaving. */
     private boolean mIsPipWindowingModeChanging;
@@ -72,7 +72,7 @@
     private ArrayList<RemoteAction> mActions = new ArrayList<>();
     private float mAspectRatio = -1f;
 
-    // Used to calculate stack bounds across rotations
+    // Used to calculate task bounds across rotations
     private final DisplayInfo mDisplayInfo = new DisplayInfo();
 
     // The aspect ratio bounds of the PIP.
@@ -85,19 +85,19 @@
     /**
      * Handler for the case where the listener dies.
      */
-    private class PinnedStackListenerDeathHandler implements IBinder.DeathRecipient {
+    private class PinnedTaskListenerDeathHandler implements IBinder.DeathRecipient {
 
         @Override
         public void binderDied() {
             // Clean up the state if the listener dies
-            if (mPinnedStackListener != null) {
-                mPinnedStackListener.asBinder().unlinkToDeath(mPinnedStackListenerDeathHandler, 0);
+            if (mPinnedTaskListener != null) {
+                mPinnedTaskListener.asBinder().unlinkToDeath(mPinnedTaskListenerDeathHandler, 0);
             }
-            mPinnedStackListener = null;
+            mPinnedTaskListener = null;
         }
     }
 
-    PinnedStackController(WindowManagerService service, DisplayContent displayContent) {
+    PinnedTaskController(WindowManagerService service, DisplayContent displayContent) {
         mService = service;
         mDisplayContent = displayContent;
         mDisplayInfo.copyFrom(mDisplayContent.getDisplayInfo());
@@ -121,17 +121,17 @@
     }
 
     /**
-     * Registers a pinned stack listener.
+     * Registers a pinned task listener.
      */
-    void registerPinnedStackListener(IPinnedStackListener listener) {
+    void registerPinnedTaskListener(IPinnedTaskListener listener) {
         try {
-            listener.asBinder().linkToDeath(mPinnedStackListenerDeathHandler, 0);
-            mPinnedStackListener = listener;
+            listener.asBinder().linkToDeath(mPinnedTaskListenerDeathHandler, 0);
+            mPinnedTaskListener = listener;
             notifyImeVisibilityChanged(mIsImeShowing, mImeHeight);
             notifyMovementBoundsChanged(false /* fromImeAdjustment */);
             notifyActionsChanged(mActions);
         } catch (RemoteException e) {
-            Log.e(TAG, "Failed to register pinned stack listener", e);
+            Log.e(TAG, "Failed to register pinned task listener", e);
         }
     }
 
@@ -139,8 +139,8 @@
      * @return whether the given {@param aspectRatio} is valid.
      */
     public boolean isValidPictureInPictureAspectRatio(float aspectRatio) {
-        return Float.compare(mMinAspectRatio, aspectRatio) <= 0 &&
-                Float.compare(aspectRatio, mMaxAspectRatio) <= 0;
+        return Float.compare(mMinAspectRatio, aspectRatio) <= 0
+                && Float.compare(aspectRatio, mMaxAspectRatio) <= 0;
     }
 
     /** Returns {@code true} if the PiP is on screen or is changing windowing mode. */
@@ -152,7 +152,7 @@
         return pinnedTask != null && pinnedTask.hasChild();
     }
 
-    /** Sets whether a visible stack is changing from or to pinned mode. */
+    /** Sets whether a visible task is changing from or to pinned mode. */
     void setPipWindowingModeChanging(boolean isPipWindowingModeChanging) {
         mIsPipWindowingModeChanging = isPipWindowingModeChanging;
     }
@@ -162,9 +162,9 @@
      * so that the default bounds will be returned for the next session.
      */
     void onActivityHidden(ComponentName componentName) {
-        if (mPinnedStackListener == null) return;
+        if (mPinnedTaskListener == null) return;
         try {
-            mPinnedStackListener.onActivityHidden(componentName);
+            mPinnedTaskListener.onActivityHidden(componentName);
         } catch (RemoteException e) {
             Slog.e(TAG_WM, "Error delivering reset reentry fraction event.", e);
         }
@@ -223,9 +223,9 @@
      * Notifies listeners that the PIP needs to be adjusted for the IME.
      */
     private void notifyImeVisibilityChanged(boolean imeVisible, int imeHeight) {
-        if (mPinnedStackListener != null) {
+        if (mPinnedTaskListener != null) {
             try {
-                mPinnedStackListener.onImeVisibilityChanged(imeVisible, imeHeight);
+                mPinnedTaskListener.onImeVisibilityChanged(imeVisible, imeHeight);
             } catch (RemoteException e) {
                 Slog.e(TAG_WM, "Error delivering bounds changed event.", e);
             }
@@ -233,9 +233,9 @@
     }
 
     private void notifyAspectRatioChanged(float aspectRatio) {
-        if (mPinnedStackListener == null) return;
+        if (mPinnedTaskListener == null) return;
         try {
-            mPinnedStackListener.onAspectRatioChanged(aspectRatio);
+            mPinnedTaskListener.onAspectRatioChanged(aspectRatio);
         } catch (RemoteException e) {
             Slog.e(TAG_WM, "Error delivering aspect ratio changed event.", e);
         }
@@ -245,9 +245,9 @@
      * Notifies listeners that the PIP actions have changed.
      */
     private void notifyActionsChanged(List<RemoteAction> actions) {
-        if (mPinnedStackListener != null) {
+        if (mPinnedTaskListener != null) {
             try {
-                mPinnedStackListener.onActionsChanged(new ParceledListSlice(actions));
+                mPinnedTaskListener.onActionsChanged(new ParceledListSlice(actions));
             } catch (RemoteException e) {
                 Slog.e(TAG_WM, "Error delivering actions changed event.", e);
             }
@@ -259,11 +259,11 @@
      */
     private void notifyMovementBoundsChanged(boolean fromImeAdjustment) {
         synchronized (mService.mGlobalLock) {
-            if (mPinnedStackListener == null) {
+            if (mPinnedTaskListener == null) {
                 return;
             }
             try {
-                mPinnedStackListener.onMovementBoundsChanged(fromImeAdjustment);
+                mPinnedTaskListener.onMovementBoundsChanged(fromImeAdjustment);
             } catch (RemoteException e) {
                 Slog.e(TAG_WM, "Error delivering actions changed event.", e);
             }
@@ -271,7 +271,7 @@
     }
 
     void dump(String prefix, PrintWriter pw) {
-        pw.println(prefix + "PinnedStackController");
+        pw.println(prefix + "PinnedTaskController");
         pw.println(prefix + "  mIsImeShowing=" + mIsImeShowing);
         pw.println(prefix + "  mImeHeight=" + mImeHeight);
         pw.println(prefix + "  mAspectRatio=" + mAspectRatio);
diff --git a/services/core/java/com/android/server/wm/PointerEventDispatcher.java b/services/core/java/com/android/server/wm/PointerEventDispatcher.java
index 08de9b0..9bc7e93 100644
--- a/services/core/java/com/android/server/wm/PointerEventDispatcher.java
+++ b/services/core/java/com/android/server/wm/PointerEventDispatcher.java
@@ -18,6 +18,7 @@
 
 import static com.android.server.input.InputManagerService.ENABLE_PER_WINDOW_INPUT_ROTATION;
 
+import android.graphics.Point;
 import android.view.InputChannel;
 import android.view.InputDevice;
 import android.view.InputEvent;
@@ -35,6 +36,7 @@
     private PointerEventListener[] mListenersArray = new PointerEventListener[0];
 
     private final DisplayContent mDisplayContent;
+    private final Point mTmpSize = new Point();
 
     public PointerEventDispatcher(InputChannel inputChannel, DisplayContent dc) {
         super(inputChannel, UiThread.getHandler().getLooper());
@@ -48,12 +50,12 @@
                     && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
                 MotionEvent motionEvent = (MotionEvent) event;
                 if (ENABLE_PER_WINDOW_INPUT_ROTATION) {
-                    int rotation = mDisplayContent.getRotation();
+                    final int rotation = mDisplayContent.getRotation();
                     if (rotation != Surface.ROTATION_0) {
+                        mDisplayContent.getDisplay().getRealSize(mTmpSize);
                         motionEvent = MotionEvent.obtain(motionEvent);
-                        motionEvent.transform(MotionEvent.createRotateMatrix(rotation,
-                                mDisplayContent.getDisplayMetrics().widthPixels,
-                                mDisplayContent.getDisplayMetrics().heightPixels));
+                        motionEvent.transform(MotionEvent.createRotateMatrix(
+                                rotation, mTmpSize.x, mTmpSize.y));
                     }
                 }
                 PointerEventListener[] listeners;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 3f9ea1f..0e8cadb 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -650,28 +650,12 @@
     }
 
     @Override
-    void dispatchConfigurationToChildren() {
-        final Configuration configuration = getConfiguration();
-        for (int i = getChildCount() - 1; i >= 0; i--) {
-            final DisplayContent displayContent = getChildAt(i);
-            if (displayContent.isDefaultDisplay) {
-                // The global configuration is also the override configuration of default display.
-                displayContent.performDisplayOverrideConfigUpdate(configuration);
-            } else {
-                displayContent.onConfigurationChanged(configuration);
-            }
-        }
-    }
-
-    @Override
-    public void onConfigurationChanged(Configuration newParentConfig) {
-        prepareFreezingTaskBounds();
-        super.onConfigurationChanged(newParentConfig);
-    }
-
-    private void prepareFreezingTaskBounds() {
-        for (int i = mChildren.size() - 1; i >= 0; i--) {
-            mChildren.get(i).prepareFreezingTaskBounds();
+    void dispatchConfigurationToChild(DisplayContent child, Configuration config) {
+        if (child.isDefaultDisplay) {
+            // The global configuration is also the override configuration of default display.
+            child.performDisplayOverrideConfigUpdate(config);
+        } else {
+            child.onConfigurationChanged(config);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 533c82e..95a4f69e 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+import static android.util.RotationUtils.deltaRotation;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
@@ -174,7 +175,7 @@
         // apply rotation animation because there should be a top app shown as rotated. So the
         // specified original rotation customizes the direction of animation to have better look
         // when restoring the rotated app to the same rotation as current display.
-        final int delta = DisplayContent.deltaRotation(originalRotation, realOriginalRotation);
+        final int delta = deltaRotation(originalRotation, realOriginalRotation);
         final boolean flipped = delta == Surface.ROTATION_90 || delta == Surface.ROTATION_270;
         mOriginalWidth = flipped ? originalHeight : originalWidth;
         mOriginalHeight = flipped ? originalWidth : originalHeight;
@@ -330,7 +331,7 @@
         // Compute the transformation matrix that must be applied
         // to the snapshot to make it stay in the same original position
         // with the current screen rotation.
-        int delta = DisplayContent.deltaRotation(rotation, Surface.ROTATION_0);
+        int delta = deltaRotation(rotation, Surface.ROTATION_0);
         RotationAnimationUtils.createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
 
         setRotationTransform(t, mSnapshotInitialMatrix);
@@ -352,8 +353,7 @@
         mStarted = true;
 
         // Figure out how the screen has moved from the original rotation.
-        int delta = DisplayContent.deltaRotation(mCurRotation, mOriginalRotation);
-
+        int delta = deltaRotation(mCurRotation, mOriginalRotation);
 
         final boolean customAnim;
         if (exitAnim != 0 && enterAnim != 0) {
diff --git a/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
index f3859b4..a98a478 100644
--- a/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
@@ -126,11 +126,17 @@
                 Slog.w(TAG, "Cannot create GestureDetector, display removed:" + displayId);
                 return;
             }
+            onDisplayInfoChanged(info);
             mGestureDetector = new GestureDetector(mContext, new FlingGestureDetector(), mHandler) {
             };
         });
     }
 
+    void onDisplayInfoChanged(DisplayInfo info) {
+        screenWidth = info.logicalWidth;
+        screenHeight = info.logicalHeight;
+    }
+
     @Override
     public void onPointerEvent(MotionEvent event) {
         if (mGestureDetector != null && event.isTouchEvent()) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index d60b6e0..5efbb09 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -35,7 +35,6 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.app.WindowConfiguration.activityTypeToString;
-import static android.app.WindowConfiguration.isSplitScreenWindowingMode;
 import static android.app.WindowConfiguration.windowingModeToString;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -148,7 +147,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ROOT_TASK;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowManagerService.MIN_TASK_LETTERBOX_ASPECT_RATIO;
 import static com.android.server.wm.WindowManagerService.dipToPixel;
 import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_BEFORE_ANIM;
 
@@ -500,9 +498,6 @@
     // TODO: Make final
     int mUserId;
 
-    final Rect mPreparedFrozenBounds = new Rect();
-    final Configuration mPreparedFrozenMergedConfig = new Configuration();
-
     // Id of the previous display the root task was on.
     int mPrevDisplayId = INVALID_DISPLAY;
 
@@ -597,10 +592,6 @@
     @Nullable
     private ActivityRecord mResumedActivity = null;
 
-    /** Last activity that is used to compute the Task bounds. */
-    @Nullable
-    private ActivityRecord mLastTaskBoundsComputeActivity;
-
     private boolean mForceShowForAllUsers;
 
     /** When set, will force the task to report as invisible. */
@@ -841,6 +832,9 @@
     // Tracking cookie for the creation of this task.
     IBinder mLaunchCookie;
 
+    // The task will be removed when TaskOrganizer, which is managing the task, is destroyed.
+    boolean mRemoveWithTaskOrganizer;
+
     private Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
             Intent _affinityIntent, String _affinity, String _rootAffinity,
             ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
@@ -852,7 +846,8 @@
             boolean supportsPictureInPicture, boolean _realActivitySuspended,
             boolean userSetupComplete, int minWidth, int minHeight, ActivityInfo info,
             IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
-            boolean _createdByOrganizer, IBinder _launchCookie, boolean _deferTaskAppear) {
+            boolean _createdByOrganizer, IBinder _launchCookie, boolean _deferTaskAppear,
+            boolean _removeWithTaskOrganizer) {
         super(atmService.mWindowManager);
 
         mAtmService = atmService;
@@ -911,6 +906,7 @@
         mCreatedByOrganizer = _createdByOrganizer;
         mLaunchCookie = _launchCookie;
         mDeferTaskAppear = _deferTaskAppear;
+        mRemoveWithTaskOrganizer = _removeWithTaskOrganizer;
         EventLogTags.writeWmTaskCreated(mTaskId, isRootTask() ? INVALID_TASK_ID : getRootTaskId());
     }
 
@@ -1183,10 +1179,6 @@
                 mTaskSupervisor.mNoAnimActivities.add(topActivity);
             }
 
-            // We might trigger a configuration change. Save the current task bounds for freezing.
-            // TODO: Should this call be moved inside the resize method in WM?
-            toRootTask.prepareFreezingTaskBounds();
-
             if (toRootTaskWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
                     && moveRootTaskMode == REPARENT_KEEP_ROOT_TASK_AT_FRONT) {
                 // Move recents to front so it is not behind root home task when going into docked
@@ -1261,10 +1253,13 @@
      * @param info The activity info which could be different from {@code r.info} if set.
      */
     void setIntent(ActivityRecord r, @Nullable Intent intent, @Nullable ActivityInfo info) {
-        mCallingUid = r.launchedFromUid;
-        mCallingPackage = r.launchedFromPackage;
-        mCallingFeatureId = r.launchedFromFeatureId;
-        setIntent(intent != null ? intent : r.intent, info != null ? info : r.info);
+        if (this.intent == null || !mNeverRelinquishIdentity) {
+            mCallingUid = r.launchedFromUid;
+            mCallingPackage = r.launchedFromPackage;
+            mCallingFeatureId = r.launchedFromFeatureId;
+            setIntent(intent != null ? intent : r.intent, info != null ? info : r.info);
+            return;
+        }
         setLockTaskAuth(r);
     }
 
@@ -1272,13 +1267,7 @@
     private void setIntent(Intent _intent, ActivityInfo info) {
         if (!isLeafTask()) return;
 
-        if (intent == null) {
-            mNeverRelinquishIdentity =
-                    (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
-        } else if (mNeverRelinquishIdentity) {
-            return;
-        }
-
+        mNeverRelinquishIdentity = (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
         affinity = info.taskAffinity;
         if (intent == null) {
             // If this task already has an intent associated with it, don't set the root
@@ -1496,11 +1485,6 @@
     }
 
     void cleanUpActivityReferences(ActivityRecord r) {
-        // mLastTaskBoundsComputeActivity is set at leaf Task
-        if (mLastTaskBoundsComputeActivity == r) {
-            mLastTaskBoundsComputeActivity = null;
-        }
-
         // mPausingActivity is set at leaf task
         if (mPausingActivity != null && mPausingActivity == r) {
             mPausingActivity = null;
@@ -2267,7 +2251,7 @@
         }
 
         if (pipChanging) {
-            mDisplayContent.getPinnedStackController().setPipWindowingModeChanging(true);
+            mDisplayContent.getPinnedTaskController().setPipWindowingModeChanging(true);
             // If the top activity is using fixed rotation, it should be changing from PiP to
             // fullscreen with display orientation change. Do not notify fullscreen task organizer
             // because the restoration of task surface and the transformation of activity surface
@@ -2297,7 +2281,7 @@
             }
         } finally {
             if (pipChanging) {
-                mDisplayContent.getPinnedStackController().setPipWindowingModeChanging(false);
+                mDisplayContent.getPinnedTaskController().setPipWindowingModeChanging(false);
             }
         }
 
@@ -2361,9 +2345,7 @@
             final int newRotation = getWindowConfiguration().getRotation();
             final boolean rotationChanged = prevRotation != newRotation;
             if (rotationChanged) {
-                mDisplayContent.rotateBounds(
-                        newParentConfig.windowConfiguration.getBounds(), prevRotation, newRotation,
-                        newBounds);
+                mDisplayContent.rotateBounds(prevRotation, newRotation, newBounds);
                 setBounds(newBounds);
             }
         }
@@ -2849,8 +2831,6 @@
                     windowingMode != WINDOWING_MODE_UNDEFINED ? windowingMode : parentWindowingMode;
             if (WindowConfiguration.inMultiWindowMode(candidateWindowingMode)
                     && candidateWindowingMode != WINDOWING_MODE_PINNED
-                    && (candidateWindowingMode != WINDOWING_MODE_FREEFORM
-                            || !mTaskSupervisor.mService.mSizeCompatFreeform)
                     && !mTaskSupervisor.mService.mSupportsNonResizableMultiWindow) {
                 getResolvedOverrideConfiguration().windowConfiguration.setWindowingMode(
                         WINDOWING_MODE_FULLSCREEN);
@@ -2865,7 +2845,6 @@
 
     private void resolveLeafOnlyOverrideConfigs(Configuration newParentConfig,
             Rect previousBounds) {
-        mLastTaskBoundsComputeActivity = getTopNonFinishingActivity(false /* includeOverlays */);
 
         int windowingMode =
                 getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode();
@@ -2879,7 +2858,8 @@
                 getResolvedOverrideConfiguration().windowConfiguration.getBounds();
 
         if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
-            computeFullscreenBounds(outOverrideBounds, newParentConfig);
+            // Use empty bounds to indicate "fill parent".
+            outOverrideBounds.setEmpty();
             // The bounds for fullscreen mode shouldn't be adjusted by minimal size. Otherwise if
             // the parent or display is smaller than the size, the content may be cropped.
             return;
@@ -2890,21 +2870,6 @@
             computeFreeformBounds(outOverrideBounds, newParentConfig);
             return;
         }
-
-        if (isSplitScreenWindowingMode(windowingMode)
-                || windowingMode == WINDOWING_MODE_MULTI_WINDOW) {
-            // This is to compute whether the task should be letterboxed to handle non-resizable app
-            // in multi window. There is no split screen only logic.
-            computeLetterboxBounds(outOverrideBounds, newParentConfig);
-        }
-    }
-
-    /** Computes bounds for {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN}. */
-    @VisibleForTesting
-    void computeFullscreenBounds(@NonNull Rect outBounds, @NonNull Configuration newParentConfig) {
-        // In FULLSCREEN mode, always start with empty bounds to indicate "fill parent".
-        outBounds.setEmpty();
-        computeLetterboxBounds(outBounds, newParentConfig);
     }
 
     /** Computes bounds for {@link WindowConfiguration#WINDOWING_MODE_FREEFORM}. */
@@ -2936,94 +2901,6 @@
         }
     }
 
-    /**
-     * Computes bounds (letterbox or pillarbox) when the parent doesn't handle the orientation
-     * change and the requested orientation is different from the parent.
-     */
-    private void computeLetterboxBounds(@NonNull Rect outBounds,
-            @NonNull Configuration newParentConfig) {
-        if (handlesOrientationChangeFromDescendant()) {
-            // No need to letterbox at task level. Display will handle fixed-orientation requests.
-            return;
-        }
-
-        final int parentOrientation = newParentConfig.orientation;
-        // Use the top activity as the reference of orientation. Don't include overlays because
-        // it is usually not the actual content or just temporarily shown.
-        // E.g. ForcedResizableInfoActivity.
-        final ActivityRecord refActivity = getTopNonFinishingActivity(false /* includeOverlays */);
-
-        // If the task or the reference activity requires a different orientation (either by
-        // override or activityInfo), make it fit the available bounds by scaling down its bounds.
-        final int overrideOrientation = getRequestedOverrideConfiguration().orientation;
-        final int forcedOrientation =
-                (overrideOrientation != ORIENTATION_UNDEFINED || refActivity == null)
-                        ? overrideOrientation : refActivity.getRequestedConfigurationOrientation();
-        if (forcedOrientation == ORIENTATION_UNDEFINED || forcedOrientation == parentOrientation) {
-            return;
-        }
-
-        final ActivityRecord.CompatDisplayInsets compatDisplayInsets =
-                refActivity == null ? null : refActivity.getCompatDisplayInsets();
-        if (compatDisplayInsets != null && !compatDisplayInsets.mIsTaskLetterboxed) {
-            // App prefers to keep its original size.
-            // If the size compat is from previous task letterboxing, we may want to have task
-            // letterbox again, otherwise it will show the size compat restart button even if the
-            // restart bounds will be the same.
-            return;
-        }
-
-        final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
-        final int parentWidth = parentBounds.width();
-        final int parentHeight = parentBounds.height();
-        float aspect = Math.max(parentWidth, parentHeight)
-                / (float) Math.min(parentWidth, parentHeight);
-
-        // Adjust the Task letterbox bounds to fit the app request aspect ratio in order to use the
-        // extra available space.
-        if (refActivity != null) {
-            final float maxAspectRatio = refActivity.info.maxAspectRatio;
-            final float minAspectRatio = refActivity.info.minAspectRatio;
-            if (aspect > maxAspectRatio && maxAspectRatio != 0) {
-                aspect = maxAspectRatio;
-            } else if (aspect < minAspectRatio) {
-                aspect = minAspectRatio;
-            }
-        }
-
-        // Override from config_letterboxAspectRatio or via ADB with set-letterbox-aspect-ratio.
-        final float letterboxAspectRatioOverride = mWmService.getTaskLetterboxAspectRatio();
-        // Activity min/max aspect ratio restrictions will be respected by the activity-level
-        // letterboxing (size-compat mode). Therefore this override can control the maximum screen
-        // area that can be occupied by the app in the letterbox mode.
-        aspect = letterboxAspectRatioOverride > MIN_TASK_LETTERBOX_ASPECT_RATIO
-                ? letterboxAspectRatioOverride : aspect;
-
-        // Store the current bounds to be able to revert to size compat mode values below if needed.
-        mTmpFullBounds.set(outBounds);
-        if (forcedOrientation == ORIENTATION_LANDSCAPE) {
-            final int height = (int) Math.rint(parentWidth / aspect);
-            final int top = parentBounds.centerY() - height / 2;
-            outBounds.set(parentBounds.left, top, parentBounds.right, top + height);
-        } else {
-            final int width = (int) Math.rint(parentHeight / aspect);
-            final int left = parentBounds.centerX() - width / 2;
-            outBounds.set(left, parentBounds.top, left + width, parentBounds.bottom);
-        }
-
-        if (compatDisplayInsets != null) {
-            compatDisplayInsets.getBoundsByRotation(
-                    mTmpBounds, newParentConfig.windowConfiguration.getRotation());
-            if (outBounds.width() != mTmpBounds.width()
-                    || outBounds.height() != mTmpBounds.height()) {
-                // The app shouldn't be resized, we only do task letterboxing if the compat bounds
-                // is also from the same task letterbox. Otherwise, clear the task bounds to show
-                // app in size compat mode.
-                outBounds.set(mTmpFullBounds);
-            }
-        }
-    }
-
     Rect updateOverrideConfigurationFromLaunchBounds() {
         // If the task is controlled by another organized task, do not set override
         // configurations and let its parent (organized task) to control it;
@@ -3038,11 +2915,6 @@
         return bounds;
     }
 
-    @Nullable
-    ActivityRecord getLastTaskBoundsComputeActivity() {
-        return mLastTaskBoundsComputeActivity;
-    }
-
     /** Updates the task's bounds and override configuration to match what is expected for the
      * input root task. */
     void updateOverrideConfigurationForRootTask(Task inRootTask) {
@@ -3484,15 +3356,6 @@
         return isResizeable();
     }
 
-    /**
-     * Prepares the task bounds to be frozen with the current size. See
-     * {@link ActivityRecord#freezeBounds}.
-     */
-    void prepareFreezingBounds() {
-        mPreparedFrozenBounds.set(getBounds());
-        mPreparedFrozenMergedConfig.setTo(getConfiguration());
-    }
-
     @Override
     void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets,
             Rect outSurfaceInsets) {
@@ -3941,12 +3804,6 @@
                 || activityType == ACTIVITY_TYPE_ASSISTANT;
     }
 
-    boolean isTaskLetterboxed() {
-        // No letterbox for multi window root task
-        return !matchParentBounds()
-                && (getWindowingMode() == WINDOWING_MODE_FULLSCREEN || !isRootTask());
-    }
-
     @Override
     boolean fillsParent() {
         // From the perspective of policy, we still want to report that this task fills parent
@@ -5185,6 +5042,10 @@
             }
         } else {
             // No longer managed by any organizer.
+            final TaskDisplayArea taskDisplayArea = getDisplayArea();
+            if (taskDisplayArea != null) {
+                taskDisplayArea.removeLaunchRootTask(this);
+            }
             setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, false /* set */);
             if (mCreatedByOrganizer) {
                 removeImmediately("setTaskOrganizer");
@@ -7626,10 +7487,6 @@
         });
     }
 
-    void prepareFreezingTaskBounds() {
-        forAllLeafTasks(Task::prepareFreezingBounds, true /* traverseTopToBottom */);
-    }
-
     private int setBounds(Rect existing, Rect bounds) {
         if (equivalentBounds(existing, bounds)) {
             return BOUNDS_CHANGE_NONE;
@@ -7792,18 +7649,18 @@
             return;
         }
 
-        final PinnedStackController pinnedStackController =
-                getDisplayContent().getPinnedStackController();
+        final PinnedTaskController pinnedTaskController =
+                getDisplayContent().getPinnedTaskController();
 
-        if (Float.compare(aspectRatio, pinnedStackController.getAspectRatio()) == 0) {
+        if (Float.compare(aspectRatio, pinnedTaskController.getAspectRatio()) == 0) {
             return;
         }
 
         // Notify the pinned stack controller about aspect ratio change.
         // This would result a callback delivered from SystemUI to WM to start animation,
         // if the bounds are ought to be altered due to aspect ratio change.
-        pinnedStackController.setAspectRatio(
-                pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)
+        pinnedTaskController.setAspectRatio(
+                pinnedTaskController.isValidPictureInPictureAspectRatio(aspectRatio)
                         ? aspectRatio : -1f);
     }
 
@@ -7819,7 +7676,7 @@
             return;
         }
 
-        getDisplayContent().getPinnedStackController().setActions(actions);
+        getDisplayContent().getPinnedTaskController().setActions(actions);
     }
 
     /** Returns true if a removal action is still being deferred. */
@@ -7972,6 +7829,7 @@
         private IBinder mLaunchCookie;
         private boolean mOnTop;
         private boolean mHasBeenVisible;
+        private boolean mRemoveWithTaskOrganizer;
 
         Builder(ActivityTaskManagerService atm) {
             mAtmService = atm;
@@ -8267,6 +8125,9 @@
             mCallingPackage = mActivityInfo.packageName;
             mResizeMode = mActivityInfo.resizeMode;
             mSupportsPictureInPicture = mActivityInfo.supportsPictureInPicture();
+            if (mActivityOptions != null) {
+                mRemoveWithTaskOrganizer = mActivityOptions.getRemoveWithTaskOranizer();
+            }
 
             final Task task = buildInner();
             task.mHasBeenVisible = mHasBeenVisible;
@@ -8305,7 +8166,7 @@
                     mCallingPackage, mCallingFeatureId, mResizeMode, mSupportsPictureInPicture,
                     mRealActivitySuspended, mUserSetupComplete, mMinWidth, mMinHeight,
                     mActivityInfo, mVoiceSession, mVoiceInteractor, mCreatedByOrganizer,
-                    mLaunchCookie, mDeferTaskAppear);
+                    mLaunchCookie, mDeferTaskAppear, mRemoveWithTaskOrganizer);
         }
     }
 }
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index 9b72570..04ec4bd 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -130,8 +130,8 @@
         l.onActivityForcedResizable((String) m.obj, m.arg1, m.arg2);
     };
 
-    private final TaskStackConsumer mNotifyActivityDismissingDockedStack = (l, m) -> {
-        l.onActivityDismissingDockedStack();
+    private final TaskStackConsumer mNotifyActivityDismissingDockedTask = (l, m) -> {
+        l.onActivityDismissingDockedTask();
     };
 
     private final TaskStackConsumer mNotifyActivityLaunchOnSecondaryDisplayFailed = (l, m) -> {
@@ -235,7 +235,7 @@
                     forAllRemoteListeners(mNotifyActivityForcedResizable, msg);
                     break;
                 case NOTIFY_ACTIVITY_DISMISSING_DOCKED_ROOT_TASK_MSG:
-                    forAllRemoteListeners(mNotifyActivityDismissingDockedStack, msg);
+                    forAllRemoteListeners(mNotifyActivityDismissingDockedTask, msg);
                     break;
                 case NOTIFY_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED_MSG:
                     forAllRemoteListeners(mNotifyActivityLaunchOnSecondaryDisplayFailed, msg);
@@ -391,7 +391,7 @@
     void notifyActivityDismissingDockedRootTask() {
         mHandler.removeMessages(NOTIFY_ACTIVITY_DISMISSING_DOCKED_ROOT_TASK_MSG);
         final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_DISMISSING_DOCKED_ROOT_TASK_MSG);
-        forAllLocalListeners(mNotifyActivityDismissingDockedStack, msg);
+        forAllLocalListeners(mNotifyActivityDismissingDockedTask, msg);
         msg.sendToTarget();
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index badd7fd..76869e5 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -1135,12 +1135,7 @@
                     "Can't set not mCreatedByOrganizer as launch root tr=" + rootTask);
         }
 
-        LaunchRootTaskDef def = null;
-        for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) {
-            if (mLaunchRootTasks.get(i).task.mTaskId != rootTask.mTaskId) continue;
-            def = mLaunchRootTasks.get(i);
-        }
-
+        LaunchRootTaskDef def = getLaunchRootTaskDef(rootTask);
         if (def != null) {
             // Remove so we add to the end of the list.
             mLaunchRootTasks.remove(def);
@@ -1156,6 +1151,23 @@
         }
     }
 
+    void removeLaunchRootTask(Task rootTask) {
+        LaunchRootTaskDef def = getLaunchRootTaskDef(rootTask);
+        if (def != null) {
+            mLaunchRootTasks.remove(def);
+        }
+    }
+
+    private @Nullable LaunchRootTaskDef getLaunchRootTaskDef(Task rootTask) {
+        LaunchRootTaskDef def = null;
+        for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) {
+            if (mLaunchRootTasks.get(i).task.mTaskId != rootTask.mTaskId) continue;
+            def = mLaunchRootTasks.get(i);
+            break;
+        }
+        return def;
+    }
+
     Task getLaunchRootTask(int windowingMode, int activityType, ActivityOptions options) {
         // Try to use the launch root task in options if available.
         if (options != null) {
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 106db0b..ee5c1f01 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -165,6 +165,10 @@
         // hasInitialBounds is set if either activity options or layout has specified bounds. If
         // that's set we'll skip some adjustments later to avoid overriding the initial bounds.
         boolean hasInitialBounds = false;
+        // hasInitialBoundsForSuggestedDisplayAreaInFreeformWindow is set if the outParams.mBounds
+        // is set with the suggestedDisplayArea. If it is set, but the eventual TaskDisplayArea is
+        // different, we should recalculating the bounds.
+        boolean hasInitialBoundsForSuggestedDisplayAreaInFreeformWindow = false;
         final boolean canApplyFreeformPolicy = canApplyFreeformWindowPolicy(display, launchMode);
         if (mSupervisor.canUseActivityOptionsLaunchBounds(options)
                 && (canApplyFreeformPolicy || canApplyPipWindowPolicy(launchMode))) {
@@ -180,11 +184,13 @@
         } else if (launchMode == WINDOWING_MODE_FULLSCREEN) {
             if (DEBUG) appendLog("activity-options-fullscreen=" + outParams.mBounds);
         } else if (layout != null && canApplyFreeformPolicy) {
-            getLayoutBounds(display, root, layout, mTmpBounds);
+            mTmpBounds.set(currentParams.mBounds);
+            getLayoutBounds(suggestedDisplayArea, root, layout, mTmpBounds);
             if (!mTmpBounds.isEmpty()) {
                 launchMode = WINDOWING_MODE_FREEFORM;
                 outParams.mBounds.set(mTmpBounds);
                 hasInitialBounds = true;
+                hasInitialBoundsForSuggestedDisplayAreaInFreeformWindow = true;
                 if (DEBUG) appendLog("bounds-from-layout=" + outParams.mBounds);
             } else {
                 if (DEBUG) appendLog("empty-window-layout");
@@ -234,19 +240,34 @@
             }
         }
 
-        // STEP 2.3: Adjust launch parameters as needed for freeform display. We enforce the policy
-        // that legacy (pre-D) apps and those apps that can't handle multiple screen density well
-        // are forced to be maximized. The rest of this step is to define the default policy when
-        // there is no initial bounds or a fully resolved current params from callers.
+        // STEP 2.3: Adjust launch parameters as needed for freeform display. We enforce the
+        // policies related to unresizable apps here. If an app is unresizable and the freeform
+        // size-compat mode is enabled, it can be launched in freeform depending on other properties
+        // such as orientation. Otherwise, the app is forcefully launched in maximized. The rest of
+        // this step is to define the default policy when there is no initial bounds or a fully
+        // resolved current params from callers.
+
+        // hasInitialBoundsForSuggestedDisplayAreaInFreeformDisplay is set if the outParams.mBounds
+        // is set with the suggestedDisplayArea. If it is set, but the eventual TaskDisplayArea is
+        // different, we should recalcuating the bounds.
+        boolean hasInitialBoundsForSuggestedDisplayAreaInFreeformDisplay = false;
         if (display.inFreeformWindowingMode()) {
             if (launchMode == WINDOWING_MODE_PINNED) {
                 if (DEBUG) appendLog("picture-in-picture");
-            } else if (!mSupervisor.mService.mSizeCompatFreeform && !root.isResizeable()) {
-                // We're launching an activity in size-compat mode and they aren't allowed in
-                // freeform, so force it to be maximized.
-                launchMode = WINDOWING_MODE_FULLSCREEN;
-                outParams.mBounds.setEmpty();
-                if (DEBUG) appendLog("forced-maximize");
+            } else if (!root.isResizeable()) {
+                if (shouldLaunchUnresizableAppInFreeform(root, suggestedDisplayArea)) {
+                    launchMode = WINDOWING_MODE_FREEFORM;
+                    if (outParams.mBounds.isEmpty()) {
+                        getTaskBounds(root, suggestedDisplayArea, layout, launchMode,
+                                hasInitialBounds, outParams.mBounds);
+                        hasInitialBoundsForSuggestedDisplayAreaInFreeformDisplay = true;
+                    }
+                    if (DEBUG) appendLog("unresizable-freeform");
+                } else {
+                    launchMode = WINDOWING_MODE_FULLSCREEN;
+                    outParams.mBounds.setEmpty();
+                    if (DEBUG) appendLog("unresizable-forced-maximize");
+                }
             }
         } else {
             if (DEBUG) appendLog("non-freeform-display");
@@ -278,6 +299,20 @@
                 mTmpDisplayArea = displayArea;
                 return true;
             });
+            // We may need to recalculate the bounds if the new TaskDisplayArea is different from
+            // the suggested one we used to calculate the bounds.
+            if (mTmpDisplayArea != null && mTmpDisplayArea != suggestedDisplayArea) {
+                if (hasInitialBoundsForSuggestedDisplayAreaInFreeformWindow) {
+                    outParams.mBounds.setEmpty();
+                    getLayoutBounds(mTmpDisplayArea, root, layout, outParams.mBounds);
+                    hasInitialBounds = !outParams.mBounds.isEmpty();
+                } else if (hasInitialBoundsForSuggestedDisplayAreaInFreeformDisplay) {
+                    outParams.mBounds.setEmpty();
+                    getTaskBounds(root, mTmpDisplayArea, layout, launchMode,
+                            hasInitialBounds, outParams.mBounds);
+                }
+            }
+
             if (mTmpDisplayArea != null) {
                 taskDisplayArea = mTmpDisplayArea;
                 mTmpDisplayArea = null;
@@ -293,7 +328,6 @@
         if (phase == PHASE_DISPLAY_AREA) {
             return RESULT_CONTINUE;
         }
-        // TODO(b/152116619): Update the usages of display to use taskDisplayArea below.
 
         // STEP 4: Determine final launch bounds based on resolved windowing mode and activity
         // requested orientation. We set bounds to empty for fullscreen mode and keep bounds as is
@@ -303,13 +337,13 @@
         // We skip making adjustments if the params are fully resolved from previous results.
         if (fullyResolvedCurrentParam) {
             if (resolvedMode == WINDOWING_MODE_FREEFORM) {
-                // Make sure bounds are in the display if it's possibly in a different display/area.
+                // Make sure bounds are in the displayArea.
                 if (currentParams.mPreferredTaskDisplayArea != taskDisplayArea) {
-                    adjustBoundsToFitInDisplay(display, outParams.mBounds);
+                    adjustBoundsToFitInDisplayArea(taskDisplayArea, outParams.mBounds);
                 }
                 // Even though we want to keep original bounds, we still don't want it to stomp on
                 // an existing task.
-                adjustBoundsToAvoidConflictInDisplay(display, outParams.mBounds);
+                adjustBoundsToAvoidConflictInDisplayArea(taskDisplayArea, outParams.mBounds);
             }
         } else if (taskDisplayArea.inFreeformWindowingMode()) {
             if (source != null && source.inFreeformWindowingMode()
@@ -318,11 +352,11 @@
                     && source.getDisplayArea() == taskDisplayArea) {
                 // Set bounds to be not very far from source activity.
                 cascadeBounds(source.getConfiguration().windowConfiguration.getBounds(),
-                        display, outParams.mBounds);
+                        taskDisplayArea, outParams.mBounds);
             }
-            getTaskBounds(root, display, layout, resolvedMode, hasInitialBounds, outParams.mBounds);
+            getTaskBounds(root, taskDisplayArea, layout, resolvedMode, hasInitialBounds,
+                    outParams.mBounds);
         }
-
         return RESULT_CONTINUE;
     }
 
@@ -491,30 +525,36 @@
                 && launchMode == WINDOWING_MODE_PINNED;
     }
 
-    private void getLayoutBounds(@NonNull DisplayContent display, @NonNull ActivityRecord root,
-            @NonNull ActivityInfo.WindowLayout windowLayout, @NonNull Rect outBounds) {
+    private void getLayoutBounds(@NonNull TaskDisplayArea displayArea, @NonNull ActivityRecord root,
+            @NonNull ActivityInfo.WindowLayout windowLayout, @NonNull Rect inOutBounds) {
         final int verticalGravity = windowLayout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
         final int horizontalGravity = windowLayout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
         if (!windowLayout.hasSpecifiedSize() && verticalGravity == 0 && horizontalGravity == 0) {
-            outBounds.setEmpty();
+            inOutBounds.setEmpty();
             return;
         }
 
         // Use stable frame instead of raw frame to avoid launching freeform windows on top of
         // stable insets, which usually are system widgets such as sysbar & navbar.
-        final Rect displayStableBounds = mTmpStableBounds;
-        display.getStableRect(displayStableBounds);
-        final int defaultWidth = displayStableBounds.width();
-        final int defaultHeight = displayStableBounds.height();
+        final Rect stableBounds = mTmpStableBounds;
+        displayArea.getStableRect(stableBounds);
+        final int defaultWidth = stableBounds.width();
+        final int defaultHeight = stableBounds.height();
 
         int width;
         int height;
         if (!windowLayout.hasSpecifiedSize()) {
-            outBounds.setEmpty();
-            getTaskBounds(root, display, windowLayout, WINDOWING_MODE_FREEFORM,
-                    /* hasInitialBounds */ false, outBounds);
-            width = outBounds.width();
-            height = outBounds.height();
+            if (!inOutBounds.isEmpty()) {
+                // If the bounds is resolved already and WindowLayout doesn't have any opinion on
+                // its size, use the already resolved size and apply the gravity to it.
+                width = inOutBounds.width();
+                height = inOutBounds.height();
+            } else {
+                getTaskBounds(root, displayArea, windowLayout, WINDOWING_MODE_FREEFORM,
+                        /* hasInitialBounds */ false, inOutBounds);
+                width = inOutBounds.width();
+                height = inOutBounds.height();
+            }
         } else {
             width = defaultWidth;
             if (windowLayout.width > 0 && windowLayout.width < defaultWidth) {
@@ -555,11 +595,28 @@
                 fractionOfVerticalOffset = 0.5f;
         }
 
-        outBounds.set(0, 0, width, height);
-        outBounds.offset(displayStableBounds.left, displayStableBounds.top);
+        inOutBounds.set(0, 0, width, height);
+        inOutBounds.offset(stableBounds.left, stableBounds.top);
         final int xOffset = (int) (fractionOfHorizontalOffset * (defaultWidth - width));
         final int yOffset = (int) (fractionOfVerticalOffset * (defaultHeight - height));
-        outBounds.offset(xOffset, yOffset);
+        inOutBounds.offset(xOffset, yOffset);
+    }
+
+    private boolean shouldLaunchUnresizableAppInFreeform(ActivityRecord activity,
+            TaskDisplayArea displayArea) {
+        if (!mSupervisor.mService.mSupportsNonResizableMultiWindow || activity.isResizeable()) {
+            return false;
+        }
+
+        final int displayOrientation = orientationFromBounds(displayArea.getBounds());
+        final int activityOrientation = resolveOrientation(activity, displayArea,
+                displayArea.getBounds());
+        if (displayArea.getWindowingMode() == WINDOWING_MODE_FREEFORM
+                && displayOrientation != activityOrientation) {
+            return true;
+        }
+
+        return false;
     }
 
     /**
@@ -602,19 +659,19 @@
         return orientation;
     }
 
-    private void cascadeBounds(@NonNull Rect srcBounds, @NonNull DisplayContent display,
+    private void cascadeBounds(@NonNull Rect srcBounds, @NonNull TaskDisplayArea displayArea,
             @NonNull Rect outBounds) {
         outBounds.set(srcBounds);
-        float density = (float) display.getConfiguration().densityDpi / DENSITY_DEFAULT;
+        float density = (float) displayArea.getConfiguration().densityDpi / DENSITY_DEFAULT;
         final int defaultOffset = (int) (CASCADING_OFFSET_DP * density + 0.5f);
 
-        display.getBounds(mTmpBounds);
+        displayArea.getBounds(mTmpBounds);
         final int dx = Math.min(defaultOffset, Math.max(0, mTmpBounds.right - srcBounds.right));
         final int dy = Math.min(defaultOffset, Math.max(0, mTmpBounds.bottom - srcBounds.bottom));
         outBounds.offset(dx, dy);
     }
 
-    private void getTaskBounds(@NonNull ActivityRecord root, @NonNull DisplayContent display,
+    private void getTaskBounds(@NonNull ActivityRecord root, @NonNull TaskDisplayArea displayArea,
             @NonNull ActivityInfo.WindowLayout layout, int resolvedMode, boolean hasInitialBounds,
             @NonNull Rect inOutBounds) {
         if (resolvedMode == WINDOWING_MODE_FULLSCREEN) {
@@ -633,7 +690,7 @@
             return;
         }
 
-        final int orientation = resolveOrientation(root, display, inOutBounds);
+        final int orientation = resolveOrientation(root, displayArea, inOutBounds);
         if (orientation != SCREEN_ORIENTATION_PORTRAIT
                 && orientation != SCREEN_ORIENTATION_LANDSCAPE) {
             throw new IllegalStateException(
@@ -642,7 +699,7 @@
         }
 
         // First we get the default size we want.
-        getDefaultFreeformSize(display, layout, orientation, mTmpBounds);
+        getDefaultFreeformSize(displayArea, layout, orientation, mTmpBounds);
         if (hasInitialBounds || sizeMatches(inOutBounds, mTmpBounds)) {
             // We're here because either input parameters specified initial bounds, or the suggested
             // bounds have the same size of the default freeform size. We should use the suggested
@@ -652,22 +709,24 @@
                 if (DEBUG) appendLog("freeform-size-orientation-match=" + inOutBounds);
             } else {
                 // Meh, orientation doesn't match. Let's rotate inOutBounds in-place.
-                centerBounds(display, inOutBounds.height(), inOutBounds.width(), inOutBounds);
+                centerBounds(displayArea, inOutBounds.height(), inOutBounds.width(),
+                        inOutBounds);
                 if (DEBUG) appendLog("freeform-orientation-mismatch=" + inOutBounds);
             }
         } else {
             // We are here either because there is no suggested bounds, or the suggested bounds is
             // a cascade from source activity. We should use the default freeform size and center it
-            // to the center of suggested bounds (or the display if no suggested bounds). The
-            // default size might be too big to center to source activity bounds in display, so we
-            // may need to move it back to the display.
-            centerBounds(display, mTmpBounds.width(), mTmpBounds.height(), inOutBounds);
-            adjustBoundsToFitInDisplay(display, inOutBounds);
+            // to the center of suggested bounds (or the displayArea if no suggested bounds). The
+            // default size might be too big to center to source activity bounds in displayArea, so
+            // we may need to move it back to the displayArea.
+            centerBounds(displayArea, mTmpBounds.width(), mTmpBounds.height(),
+                    inOutBounds);
+            adjustBoundsToFitInDisplayArea(displayArea, inOutBounds);
             if (DEBUG) appendLog("freeform-size-mismatch=" + inOutBounds);
         }
 
         // Lastly we adjust bounds to avoid conflicts with other tasks as much as possible.
-        adjustBoundsToAvoidConflictInDisplay(display, inOutBounds);
+        adjustBoundsToAvoidConflictInDisplayArea(displayArea, inOutBounds);
     }
 
     private int convertOrientationToScreenOrientation(int orientation) {
@@ -681,13 +740,14 @@
         }
     }
 
-    private int resolveOrientation(@NonNull ActivityRecord root, @NonNull DisplayContent display,
-            @NonNull Rect bounds) {
+    private int resolveOrientation(@NonNull ActivityRecord root,
+            @NonNull TaskDisplayArea displayArea, @NonNull Rect bounds) {
         int orientation = resolveOrientation(root);
 
         if (orientation == SCREEN_ORIENTATION_LOCKED) {
             orientation = bounds.isEmpty()
-                    ? convertOrientationToScreenOrientation(display.getConfiguration().orientation)
+                    ? convertOrientationToScreenOrientation(
+                            displayArea.getConfiguration().orientation)
                     : orientationFromBounds(bounds);
             if (DEBUG) {
                 appendLog(bounds.isEmpty() ? "locked-orientation-from-display=" + orientation
@@ -707,19 +767,17 @@
         return orientation;
     }
 
-    private void getDefaultFreeformSize(@NonNull DisplayContent display,
+    private void getDefaultFreeformSize(@NonNull TaskDisplayArea displayArea,
             @NonNull ActivityInfo.WindowLayout layout, int orientation, @NonNull Rect bounds) {
-        // Default size, which is letterboxing/pillarboxing in display. That's to say the large
-        // dimension of default size is the small dimension of display size, and the small dimension
-        // of default size is calculated to keep the same aspect ratio as the display's. Here we use
-        // stable bounds of displays because that indicates the area that isn't occupied by system
-        // widgets (e.g. sysbar and navbar).
-        final Rect displayStableBounds = mTmpStableBounds;
-        display.getStableRect(displayStableBounds);
-        final int portraitHeight =
-                Math.min(displayStableBounds.width(), displayStableBounds.height());
-        final int otherDimension =
-                Math.max(displayStableBounds.width(), displayStableBounds.height());
+        // Default size, which is letterboxing/pillarboxing in displayArea. That's to say the large
+        // dimension of default size is the small dimension of displayArea size, and the small
+        // dimension of default size is calculated to keep the same aspect ratio as the
+        // displayArea's. Here we use stable bounds of displayArea because that indicates the area
+        // that isn't occupied by system widgets (e.g. sysbar and navbar).
+        final Rect stableBounds = mTmpStableBounds;
+        displayArea.getStableRect(stableBounds);
+        final int portraitHeight = Math.min(stableBounds.width(), stableBounds.height());
+        final int otherDimension = Math.max(stableBounds.width(), stableBounds.height());
         final int portraitWidth = (portraitHeight * portraitHeight) / otherDimension;
         final int defaultWidth = (orientation == SCREEN_ORIENTATION_LANDSCAPE) ? portraitHeight
                 : portraitWidth;
@@ -728,7 +786,7 @@
 
         // Get window size based on Nexus 5x screen, we assume that this is enough to show content
         // of activities.
-        final float density = (float) display.getConfiguration().densityDpi / DENSITY_DEFAULT;
+        final float density = (float) displayArea.getConfiguration().densityDpi / DENSITY_DEFAULT;
         final int phonePortraitWidth = (int) (DEFAULT_PORTRAIT_PHONE_WIDTH_DP * density + 0.5f);
         final int phonePortraitHeight = (int) (DEFAULT_PORTRAIT_PHONE_HEIGHT_DP * density + 0.5f);
         final int phoneWidth = (orientation == SCREEN_ORIENTATION_LANDSCAPE) ? phonePortraitHeight
@@ -745,83 +803,83 @@
         final int height = Math.min(defaultHeight, Math.max(phoneHeight, layoutMinHeight));
 
         bounds.set(0, 0, width, height);
-        bounds.offset(displayStableBounds.left, displayStableBounds.top);
+        bounds.offset(stableBounds.left, stableBounds.top);
     }
 
     /**
      * Gets centered bounds of width x height. If inOutBounds is not empty, the result bounds
-     * centers at its center or display's app bounds center if inOutBounds is empty.
+     * centers at its center or displayArea's app bounds center if inOutBounds is empty.
      */
-    private void centerBounds(@NonNull DisplayContent display, int width, int height,
+    private void centerBounds(@NonNull TaskDisplayArea displayArea, int width, int height,
             @NonNull Rect inOutBounds) {
         if (inOutBounds.isEmpty()) {
-            display.getStableRect(inOutBounds);
+            displayArea.getStableRect(inOutBounds);
         }
         final int left = inOutBounds.centerX() - width / 2;
         final int top = inOutBounds.centerY() - height / 2;
         inOutBounds.set(left, top, left + width, top + height);
     }
 
-    private void adjustBoundsToFitInDisplay(@NonNull DisplayContent display,
+    private void adjustBoundsToFitInDisplayArea(@NonNull TaskDisplayArea displayArea,
             @NonNull Rect inOutBounds) {
-        final Rect displayStableBounds = mTmpStableBounds;
-        display.getStableRect(displayStableBounds);
+        final Rect stableBounds = mTmpStableBounds;
+        displayArea.getStableRect(stableBounds);
 
-        if (displayStableBounds.width() < inOutBounds.width()
-                || displayStableBounds.height() < inOutBounds.height()) {
-            // There is no way for us to fit the bounds in the display without changing width
-            // or height. Just move the start to align with the display.
+        if (stableBounds.width() < inOutBounds.width()
+                || stableBounds.height() < inOutBounds.height()) {
+            // There is no way for us to fit the bounds in the displayArea without changing width
+            // or height. Just move the start to align with the displayArea.
             final int layoutDirection =
                     mSupervisor.mRootWindowContainer.getConfiguration().getLayoutDirection();
             final int left = layoutDirection == View.LAYOUT_DIRECTION_RTL
-                    ? displayStableBounds.right - inOutBounds.right + inOutBounds.left
-                    : displayStableBounds.left;
-            inOutBounds.offsetTo(left, displayStableBounds.top);
+                    ? stableBounds.right - inOutBounds.right + inOutBounds.left
+                    : stableBounds.left;
+            inOutBounds.offsetTo(left, stableBounds.top);
             return;
         }
 
         final int dx;
-        if (inOutBounds.right > displayStableBounds.right) {
-            // Right edge is out of display.
-            dx = displayStableBounds.right - inOutBounds.right;
-        } else if (inOutBounds.left < displayStableBounds.left) {
-            // Left edge is out of display.
-            dx = displayStableBounds.left - inOutBounds.left;
+        if (inOutBounds.right > stableBounds.right) {
+            // Right edge is out of displayArea.
+            dx = stableBounds.right - inOutBounds.right;
+        } else if (inOutBounds.left < stableBounds.left) {
+            // Left edge is out of displayArea.
+            dx = stableBounds.left - inOutBounds.left;
         } else {
-            // Vertical edges are all in display.
+            // Vertical edges are all in displayArea.
             dx = 0;
         }
 
         final int dy;
-        if (inOutBounds.top < displayStableBounds.top) {
-            // Top edge is out of display.
-            dy = displayStableBounds.top - inOutBounds.top;
-        } else if (inOutBounds.bottom > displayStableBounds.bottom) {
-            // Bottom edge is out of display.
-            dy = displayStableBounds.bottom - inOutBounds.bottom;
+        if (inOutBounds.top < stableBounds.top) {
+            // Top edge is out of displayArea.
+            dy = stableBounds.top - inOutBounds.top;
+        } else if (inOutBounds.bottom > stableBounds.bottom) {
+            // Bottom edge is out of displayArea.
+            dy = stableBounds.bottom - inOutBounds.bottom;
         } else {
-            // Horizontal edges are all in display.
+            // Horizontal edges are all in displayArea.
             dy = 0;
         }
         inOutBounds.offset(dx, dy);
     }
 
     /**
-     * Adjusts input bounds to avoid conflict with existing tasks in the display.
+     * Adjusts input bounds to avoid conflict with existing tasks in the displayArea.
      *
      * If the input bounds conflict with existing tasks, this method scans the bounds in a series of
-     * directions to find a location where the we can put the bounds in display without conflict
+     * directions to find a location where the we can put the bounds in displayArea without conflict
      * with any other tasks.
      *
-     * It doesn't try to adjust bounds that's not fully in the given display.
+     * It doesn't try to adjust bounds that's not fully in the given displayArea.
      *
-     * @param display the display which tasks are to check
+     * @param displayArea the displayArea which tasks are to check
      * @param inOutBounds the bounds used to input initial bounds and output result bounds
      */
-    private void adjustBoundsToAvoidConflictInDisplay(@NonNull DisplayContent display,
+    private void adjustBoundsToAvoidConflictInDisplayArea(@NonNull TaskDisplayArea displayArea,
             @NonNull Rect inOutBounds) {
         final List<Rect> taskBoundsToCheck = new ArrayList<>();
-        display.forAllRootTasks(task -> {
+        displayArea.forAllRootTasks(task -> {
             if (!task.inFreeformWindowingMode()) {
                 return;
             }
@@ -830,28 +888,28 @@
                 taskBoundsToCheck.add(task.getChildAt(j).getBounds());
             }
         }, false /* traverseTopToBottom */);
-        adjustBoundsToAvoidConflict(display.getBounds(), taskBoundsToCheck, inOutBounds);
+        adjustBoundsToAvoidConflict(displayArea.getBounds(), taskBoundsToCheck, inOutBounds);
     }
 
     /**
-     * Adjusts input bounds to avoid conflict with provided display bounds and list of tasks bounds
-     * for the display.
+     * Adjusts input bounds to avoid conflict with provided displayArea bounds and list of tasks
+     * bounds for the displayArea.
      *
      * Scans the bounds in directions to find a candidate location that does not conflict with the
-     * provided list of task bounds. If starting bounds are outside the display bounds or if no
+     * provided list of task bounds. If starting bounds are outside the displayArea bounds or if no
      * suitable candidate bounds are found, the method returns the input bounds.
      *
-     * @param displayBounds display bounds used to restrict the candidate bounds
+     * @param displayAreaBounds displayArea bounds used to restrict the candidate bounds
      * @param taskBoundsToCheck list of task bounds to check for conflict
      * @param inOutBounds the bounds used to input initial bounds and output result bounds
      */
     @VisibleForTesting
-    void adjustBoundsToAvoidConflict(@NonNull Rect displayBounds,
+    void adjustBoundsToAvoidConflict(@NonNull Rect displayAreaBounds,
             @NonNull List<Rect> taskBoundsToCheck,
             @NonNull Rect inOutBounds) {
-        if (!displayBounds.contains(inOutBounds)) {
-            // The initial bounds are already out of display. The scanning algorithm below doesn't
-            // work so well with them.
+        if (!displayAreaBounds.contains(inOutBounds)) {
+            // The initial bounds are already out of displayArea. The scanning algorithm below
+            // doesn't work so well with them.
             return;
         }
 
@@ -861,7 +919,7 @@
             return;
         }
 
-        calculateCandidateShiftDirections(displayBounds, inOutBounds);
+        calculateCandidateShiftDirections(displayAreaBounds, inOutBounds);
         for (int direction : mTmpDirections) {
             if (direction == Gravity.NO_GRAVITY) {
                 // We exhausted candidate directions, give up.
@@ -870,12 +928,12 @@
 
             mTmpBounds.set(inOutBounds);
             while (boundsConflict(taskBoundsToCheck, mTmpBounds)
-                    && displayBounds.contains(mTmpBounds)) {
-                shiftBounds(direction, displayBounds, mTmpBounds);
+                    && displayAreaBounds.contains(mTmpBounds)) {
+                shiftBounds(direction, displayAreaBounds, mTmpBounds);
             }
 
             if (!boundsConflict(taskBoundsToCheck, mTmpBounds)
-                    && displayBounds.contains(mTmpBounds)) {
+                    && displayAreaBounds.contains(mTmpBounds)) {
                 // Found a candidate. Just use this.
                 inOutBounds.set(mTmpBounds);
                 if (DEBUG) appendLog("avoid-bounds-conflict=" + inOutBounds);
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index c0bce6b..fc6db61 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -285,18 +285,20 @@
             return false;
         }
 
-        private boolean removeTask(Task t) {
+        private boolean removeTask(Task t, boolean removeFromSystem) {
             mOrganizedTasks.remove(t);
             mInterceptBackPressedOnRootTasks.remove(t.mTaskId);
-
-            if (t.mTaskAppearedSent) {
+            boolean taskAppearedSent = t.mTaskAppearedSent;
+            if (taskAppearedSent) {
                 if (t.getSurfaceControl() != null) {
                     t.migrateToNewSurfaceControl();
                 }
                 t.mTaskAppearedSent = false;
-                return true;
             }
-            return false;
+            if (removeFromSystem) {
+                mService.removeTask(t.mTaskId);
+            }
+            return taskAppearedSent;
         }
 
         void dispose() {
@@ -311,7 +313,7 @@
                 if (mOrganizedTasks.contains(t)) {
                     // updateTaskOrganizerState should remove the task from the list, but still
                     // check it again to avoid while-loop isn't terminate.
-                    if (removeTask(t)) {
+                    if (removeTask(t, t.mRemoveWithTaskOrganizer)) {
                         TaskOrganizerController.this.onTaskVanishedInternal(
                                 mOrganizer.mTaskOrganizer, t);
                     }
@@ -527,7 +529,7 @@
 
     void onTaskVanished(ITaskOrganizer organizer, Task task) {
         final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
-        if (state != null && state.removeTask(task)) {
+        if (state != null && state.removeTask(task, false /* removeFromSystem */)) {
             onTaskVanishedInternal(organizer, task);
         }
     }
@@ -596,9 +598,7 @@
         try {
             synchronized (mGlobalLock) {
                 final WindowContainer wc = WindowContainer.fromBinder(token.asBinder());
-                if (wc == null) {
-                    throw new IllegalArgumentException("Can't resolve window from token");
-                }
+                if (wc == null) return false;
                 final Task task = wc.asTask();
                 if (task == null) return false;
                 if (!task.mCreatedByOrganizer) {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index dd4ee877..000889a 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -2684,14 +2684,6 @@
             @Nullable ArrayList<WindowContainer> sources) {
         final Task task = asTask();
         if (task != null && !enter && !task.isHomeOrRecentsRootTask()) {
-            if (AppTransition.isClosingTransitOld(transit)) {
-                // Freezes the insets state when the window is in app exiting transition, to
-                // ensure the exiting window won't receive unexpected insets changes from the
-                // next window.
-                task.forAllWindows(w -> {
-                    w.freezeInsetsState();
-                }, true /* traverseTopToBottom */);
-            }
             mDisplayContent.showImeScreenshot();
         }
         final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp,
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index e183ea0..7450782 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -66,7 +66,7 @@
         /**
          * Is trace enabled or not.
          */
-        boolean isEnabled();
+        boolean isAccessibilityTracingEnabled();
 
         /**
          * Add an accessibility trace entry.
@@ -667,4 +667,13 @@
      * Moves the {@link WindowToken} {@code binder} to the display specified by {@code displayId}.
      */
     public abstract void moveWindowTokenToDisplay(IBinder binder, int displayId);
+
+    /**
+     * Checks whether the given window should restore the last IME visibility.
+     *
+     * @param imeTargetWindowToken The token of the (IME target) window
+     * @return {@code true} when the system allows to restore the IME visibility,
+     *         {@code false} otherwise.
+     */
+    public abstract boolean shouldRestoreImeVisibility(IBinder imeTargetWindowToken);
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 89d3040..70b0f58 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -39,7 +39,6 @@
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW;
-import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
 import static android.provider.Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR;
@@ -224,13 +223,14 @@
 import android.view.DisplayInfo;
 import android.view.Gravity;
 import android.view.IAppTransitionAnimationSpecsFuture;
+import android.view.ICrossWindowBlurEnabledListener;
 import android.view.IDisplayFoldListener;
 import android.view.IDisplayWindowInsetsController;
 import android.view.IDisplayWindowListener;
 import android.view.IDisplayWindowRotationController;
 import android.view.IInputFilter;
 import android.view.IOnKeyguardExitResult;
-import android.view.IPinnedStackListener;
+import android.view.IPinnedTaskListener;
 import android.view.IRecentsAnimationRunner;
 import android.view.IRotationWatcher;
 import android.view.IScrollCaptureCallbacks;
@@ -253,6 +253,7 @@
 import android.view.MotionEvent;
 import android.view.PointerIcon;
 import android.view.RemoteAnimationAdapter;
+import android.view.ScrollCaptureResponse;
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
@@ -756,6 +757,8 @@
 
     final TaskSnapshotController mTaskSnapshotController;
 
+    final BlurController mBlurController = new BlurController();
+
     boolean mIsTouchDevice;
     boolean mIsFakeTouchDevice;
 
@@ -802,8 +805,6 @@
                 Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT);
         private final Uri mForceResizableUri = Settings.Global.getUriFor(
                 DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES);
-        private final Uri mSizeCompatFreeformUri = Settings.Global.getUriFor(
-                DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM);
         private final Uri mSupportsNonResizableMultiWindowUri = Settings.Global.getUriFor(
                 DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW);
         private final Uri mRenderShadowsInCompositorUri = Settings.Global.getUriFor(
@@ -830,8 +831,6 @@
                     UserHandle.USER_ALL);
             resolver.registerContentObserver(mFreeformWindowUri, false, this, UserHandle.USER_ALL);
             resolver.registerContentObserver(mForceResizableUri, false, this, UserHandle.USER_ALL);
-            resolver.registerContentObserver(mSizeCompatFreeformUri, false, this,
-                    UserHandle.USER_ALL);
             resolver.registerContentObserver(mSupportsNonResizableMultiWindowUri, false, this,
                     UserHandle.USER_ALL);
             resolver.registerContentObserver(mRenderShadowsInCompositorUri, false, this,
@@ -871,11 +870,6 @@
                 return;
             }
 
-            if (mSizeCompatFreeformUri.equals(uri)) {
-                updateSizeCompatFreeform();
-                return;
-            }
-
             if (mSupportsNonResizableMultiWindowUri.equals(uri)) {
                 updateSupportsNonResizableMultiWindow();
                 return;
@@ -973,14 +967,6 @@
             mAtmService.mForceResizableActivities = forceResizable;
         }
 
-        void updateSizeCompatFreeform() {
-            ContentResolver resolver = mContext.getContentResolver();
-            final boolean sizeCompatFreeform = Settings.Global.getInt(resolver,
-                    DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM, 0) != 0;
-
-            mAtmService.mSizeCompatFreeform = sizeCompatFreeform;
-        }
-
         void updateSupportsNonResizableMultiWindow() {
             ContentResolver resolver = mContext.getContentResolver();
             final boolean supportsNonResizableMultiWindow = Settings.Global.getInt(resolver,
@@ -2393,15 +2379,9 @@
                 }
             }
 
-            // We may be deferring layout passes at the moment, but since the client is interested
-            // in the new out values right now we need to force a layout.
-            mWindowPlacerLocked.performSurfacePlacement(true /* force */);
-
+            // Create surfaceControl before surface placement otherwise layout will be skipped
+            // (because WS.isGoneForLayout() is true when there is no surface.
             if (shouldRelayout) {
-                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_1");
-
-                result = win.relayoutVisibleWindow(result);
-
                 try {
                     result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);
                 } catch (Exception e) {
@@ -2413,6 +2393,17 @@
                     Binder.restoreCallingIdentity(origId);
                     return 0;
                 }
+            }
+
+            // We may be deferring layout passes at the moment, but since the client is interested
+            // in the new out values right now we need to force a layout.
+            mWindowPlacerLocked.performSurfacePlacement(true /* force */);
+
+            if (shouldRelayout) {
+                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_1");
+
+                result = win.relayoutVisibleWindow(result);
+
                 if ((result & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
                     focusMayChange = true;
                 }
@@ -2981,7 +2972,7 @@
     }
 
     boolean isValidPictureInPictureAspectRatio(DisplayContent displayContent, float aspectRatio) {
-        return displayContent.getPinnedStackController().isValidPictureInPictureAspectRatio(
+        return displayContent.getPinnedTaskController().isValidPictureInPictureAspectRatio(
                 aspectRatio);
     }
 
@@ -5684,6 +5675,18 @@
         return mWindowTracing.isEnabled();
     }
 
+    @Override
+    public boolean registerCrossWindowBlurEnabledListener(
+                ICrossWindowBlurEnabledListener listener) {
+        return mBlurController.registerCrossWindowBlurEnabledListener(listener);
+    }
+
+    @Override
+    public void unregisterCrossWindowBlurEnabledListener(
+                ICrossWindowBlurEnabledListener listener) {
+        mBlurController.unregisterCrossWindowBlurEnabledListener(listener);
+    }
+
     // -------------------------------------------------------------
     // Internals
     // -------------------------------------------------------------
@@ -6423,6 +6426,7 @@
             }
         });
         pw.print("  mInTouchMode="); pw.println(mInTouchMode);
+        pw.print("  mBlurEnabled="); pw.println(mBlurController.mBlurEnabled);
         pw.print("  mLastDisplayFreezeDuration=");
                 TimeUtils.formatDuration(mLastDisplayFreezeDuration, pw);
                 if ( mLastFinishedFreezeSource != null) {
@@ -6880,7 +6884,7 @@
     }
 
     @Override
-    public void setDockedStackDividerTouchRegion(Rect touchRegion) {
+    public void setDockedTaskDividerTouchRegion(Rect touchRegion) {
         synchronized (mGlobalLock) {
             final DisplayContent dc = getDefaultDisplayContentLocked();
             dc.getDockedDividerController().setTouchRegion(touchRegion);
@@ -6905,10 +6909,9 @@
         return (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, displayMetrics);
     }
 
-    @Override
-    public void registerPinnedStackListener(int displayId, IPinnedStackListener listener) {
+    public void registerPinnedTaskListener(int displayId, IPinnedTaskListener listener) {
         if (!checkCallingPermission(REGISTER_WINDOW_MANAGER_LISTENERS,
-                "registerPinnedStackListener()")) {
+                "registerPinnedTaskListener()")) {
             return;
         }
         if (!mAtmService.mSupportsPictureInPicture) {
@@ -6916,7 +6919,7 @@
         }
         synchronized (mGlobalLock) {
             final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
-            displayContent.getPinnedStackController().registerPinnedStackListener(listener);
+            displayContent.getPinnedTaskController().registerPinnedTaskListener(listener);
         }
     }
 
@@ -7155,12 +7158,14 @@
         }
         final long token = Binder.clearCallingIdentity();
         try {
+            ScrollCaptureResponse.Builder responseBuilder = new ScrollCaptureResponse.Builder();
             synchronized (mGlobalLock) {
                 DisplayContent dc = mRoot.getDisplayContent(displayId);
                 if (dc == null) {
                     ProtoLog.e(WM_ERROR,
                             "Invalid displayId for requestScrollCapture: %d", displayId);
-                    callbacks.onUnavailable();
+                    responseBuilder.setDescription(String.format("bad displayId: %d", displayId));
+                    callbacks.onScrollCaptureResponse(responseBuilder.build());
                     return;
                 }
                 WindowState topWindow = null;
@@ -7169,17 +7174,20 @@
                 }
                 WindowState targetWindow = dc.findScrollCaptureTargetWindow(topWindow, taskId);
                 if (targetWindow == null) {
-                    callbacks.onUnavailable();
+                    responseBuilder.setDescription("findScrollCaptureTargetWindow returned null");
+                    callbacks.onScrollCaptureResponse(responseBuilder.build());
                     return;
                 }
-                // Forward to the window for handling.
                 try {
+                    // Forward to the window for handling, which will respond using the callback.
                     targetWindow.mClient.requestScrollCapture(callbacks);
                 } catch (RemoteException e) {
                     ProtoLog.w(WM_ERROR,
                             "requestScrollCapture: caught exception dispatching to window."
                                     + "token=%s", targetWindow.mClient.asBinder());
-                    callbacks.onUnavailable();
+                    responseBuilder.setWindowTitle(targetWindow.getName());
+                    responseBuilder.setDescription(String.format("caught exception: %s", e));
+                    callbacks.onScrollCaptureResponse(responseBuilder.build());
                 }
             }
         } catch (RemoteException e) {
@@ -8016,6 +8024,11 @@
                 return dc.getImeTarget(IME_TARGET_LAYERING).getWindow().getName();
             }
         }
+
+        @Override
+        public boolean shouldRestoreImeVisibility(IBinder imeTargetWindowToken) {
+            return WindowManagerService.this.shouldRestoreImeVisibility(imeTargetWindowToken);
+        }
     }
 
     void registerAppFreezeListener(AppFreezeListener listener) {
@@ -8673,6 +8686,22 @@
                 boundsInWindow, hashAlgorithm, callback);
     }
 
+    boolean shouldRestoreImeVisibility(IBinder imeTargetWindowToken) {
+        synchronized (mGlobalLock) {
+            final WindowState imeTargetWindow = mWindowMap.get(imeTargetWindowToken);
+            if (imeTargetWindow == null) {
+                return false;
+            }
+            final Task imeTargetWindowTask = imeTargetWindow.getTask();
+            if (imeTargetWindowTask == null) {
+                return false;
+            }
+            final TaskSnapshot snapshot = mAtmService.getTaskSnapshot(imeTargetWindowTask.mTaskId,
+                    false /* isLowResolution */);
+            return snapshot != null && snapshot.hasImeSurface();
+        }
+    }
+
     private void sendDisplayHashError(RemoteCallback callback, int errorCode) {
         Bundle bundle = new Bundle();
         bundle.putInt(EXTRA_DISPLAY_HASH_ERROR_CODE, errorCode);
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 63a0832..9973664 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -17,7 +17,6 @@
 package com.android.server.wm;
 
 import static android.Manifest.permission.READ_FRAME_BUFFER;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT;
@@ -426,8 +425,9 @@
         }
 
         if (windowingMode > -1) {
-            if (mService.isInLockTaskMode() && windowingMode != WINDOWING_MODE_FULLSCREEN) {
-                throw new UnsupportedOperationException("Not supported to set non-fullscreen"
+            if (mService.isInLockTaskMode()
+                    && WindowConfiguration.inMultiWindowMode(windowingMode)) {
+                throw new UnsupportedOperationException("Not supported to set multi-window"
                         + " windowing mode during locked task mode.");
             }
             container.setWindowingMode(windowingMode);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 60e95e5..fec715e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -797,7 +797,7 @@
      * {@link InsetsStateController#notifyInsetsChanged}.
      */
     boolean isReadyToDispatchInsetsState() {
-        return isVisible() && mFrozenInsetsState == null;
+        return isVisibleRequested() && mFrozenInsetsState == null;
     }
 
     void seamlesslyRotateIfAllowed(Transaction transaction, @Rotation int oldRotation,
@@ -1190,16 +1190,6 @@
             layoutYDiff = 0;
         } else {
             windowFrames.mContainingFrame.set(getBounds());
-            if (mActivityRecord != null && !mActivityRecord.mFrozenBounds.isEmpty()) {
-
-                // If the bounds are frozen, we still want to translate the window freely and only
-                // freeze the size.
-                Rect frozen = mActivityRecord.mFrozenBounds.peek();
-                windowFrames.mContainingFrame.right =
-                        windowFrames.mContainingFrame.left + frozen.width();
-                windowFrames.mContainingFrame.bottom =
-                        windowFrames.mContainingFrame.top + frozen.height();
-            }
             // IME is up and obscuring this window. Adjust the window position so it is visible.
             if (isImeTarget) {
                 if (inFreeformWindowingMode()) {
@@ -1224,7 +1214,7 @@
                     // But in docked we want to behave like fullscreen and behave as if the task
                     // were given smaller bounds for the purposes of layout. Skip adjustments for
                     // the root pinned task, they are handled separately in the
-                    // PinnedStackController.
+                    // PinnedTaskController.
                     windowFrames.mContainingFrame.bottom = windowFrames.mParentFrame.bottom;
                 }
             }
@@ -2068,23 +2058,6 @@
         super.onResize();
     }
 
-    void onUnfreezeBounds() {
-        for (int i = mChildren.size() - 1; i >= 0; --i) {
-            final WindowState c = mChildren.get(i);
-            c.onUnfreezeBounds();
-        }
-
-        if (!mHasSurface) {
-            return;
-        }
-
-        mLayoutNeeded = true;
-        setDisplayLayoutNeeded();
-        if (!mWmService.mResizingWindows.contains(this)) {
-            mWmService.mResizingWindows.add(this);
-        }
-    }
-
     /**
      * If the window has moved due to its containing content frame changing, then notify the
      * listeners and optionally animate it. Simply checking a change of position is not enough,
@@ -3579,10 +3552,6 @@
 
     @Override
     public Configuration getConfiguration() {
-        if (mActivityRecord != null && mActivityRecord.mFrozenMergedConfig.size() > 0) {
-            return mActivityRecord.mFrozenMergedConfig.peek();
-        }
-
         // If the process has not registered to any display area to listen to the configuration
         // change, we can simply return the mFullConfiguration as default.
         if (!registeredForDisplayAreaConfigChanges()) {
@@ -3827,13 +3796,21 @@
     /** @return true when the window should be letterboxed. */
     boolean isLetterboxedAppWindow() {
         // Fullscreen mode but doesn't fill display area.
-        return (!inMultiWindowMode() && !matchesDisplayAreaBounds())
-                // Activity in size compat.
-                || (mActivityRecord != null && mActivityRecord.inSizeCompatMode())
-                // Task letterboxed.
-                || (getTask() != null && getTask().isTaskLetterboxed())
-                // Letterboxed for display cutout.
-                || isLetterboxedForDisplayCutout();
+        if (!inMultiWindowMode() && !matchesDisplayAreaBounds()) {
+            return true;
+        }
+        if (mActivityRecord != null) {
+            // Activity in size compat.
+            if (mActivityRecord.inSizeCompatMode()) {
+                return true;
+            }
+            // Letterbox for fixed orientation.
+            if (mActivityRecord.isLetterboxedForFixedOrientationAndAspectRatio()) {
+                return true;
+            }
+        }
+        // Letterboxed for display cutout.
+        return isLetterboxedForDisplayCutout();
     }
 
     /** Returns {@code true} if the window is letterboxed for the display cutout. */
@@ -3936,14 +3913,8 @@
             return true;
         }
 
-        // If the bounds are currently frozen, it means that the layout size that the app sees
-        // and the bounds we clip this window to might be different. In order to avoid holes, we
-        // simulate that we are still resizing so the app fills the hole with the resizing
-        // background.
-        return (getDisplayContent().mDividerControllerLocked.isResizing()
-                        || mActivityRecord != null && !mActivityRecord.mFrozenBounds.isEmpty()) &&
-                !task.inFreeformWindowingMode() && !isGoneForLayout();
-
+        return getDisplayContent().mDividerControllerLocked.isResizing()
+                && !task.inFreeformWindowingMode() && !isGoneForLayout();
     }
 
     void setDragResizing() {
@@ -5265,22 +5236,24 @@
         if (!mAnimatingExit && mAppDied) {
             mIsDimming = true;
             getDimmer().dimAbove(getSyncTransaction(), this, DEFAULT_DIM_AMOUNT_DEAD_WINDOW);
-        } else if (((mAttrs.flags & FLAG_DIM_BEHIND) != 0 || (mAttrs.flags & FLAG_BLUR_BEHIND) != 0)
+        } else if (((mAttrs.flags & FLAG_DIM_BEHIND) != 0 || shouldDrawBlurBehind())
                    && isVisibleNow() && !mHidden) {
             // Only show the Dimmer when the following is satisfied:
-            // 1. The window has the flag FLAG_DIM_BEHIND or background blur is requested
+            // 1. The window has the flag FLAG_DIM_BEHIND or blur behind is requested
             // 2. The WindowToken is not hidden so dims aren't shown when the window is exiting.
             // 3. The WS is considered visible according to the isVisible() method
             // 4. The WS is not hidden.
             mIsDimming = true;
             final float dimAmount = (mAttrs.flags & FLAG_DIM_BEHIND) != 0 ? mAttrs.dimAmount : 0;
-            final int blurRadius =
-                    (mAttrs.flags & FLAG_BLUR_BEHIND) != 0 ? mAttrs.blurBehindRadius : 0;
-            getDimmer().dimBelow(
-                    getSyncTransaction(), this, mAttrs.dimAmount, mAttrs.blurBehindRadius);
+            final int blurRadius = shouldDrawBlurBehind() ? mAttrs.getBlurBehindRadius() : 0;
+            getDimmer().dimBelow(getSyncTransaction(), this, mAttrs.dimAmount, blurRadius);
         }
     }
 
+    private boolean shouldDrawBlurBehind() {
+        return (mAttrs.flags & FLAG_BLUR_BEHIND) != 0 && mWmService.mBlurController.mBlurEnabled;
+    }
+
     /**
      * Notifies SF about the priority of the window, if it changed. SF then uses this information
      * to decide which window's desired rendering rate should have a priority when deciding about
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index e87ee91..066cc1e 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -736,4 +736,13 @@
     boolean isFromClient() {
         return mFromClientToken;
     }
+
+    /** @see WindowState#freezeInsetsState() */
+    void setInsetsFrozen(boolean freeze) {
+        if (freeze) {
+            forAllWindows(WindowState::freezeInsetsState, true /* traverseTopToBottom */);
+        } else {
+            forAllWindows(WindowState::clearFrozenInsetsState, true /* traverseTopToBottom */);
+        }
+    }
 }
diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
index f054e7c..8c6d084 100644
--- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
+++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
@@ -232,21 +232,6 @@
     compactProcessOrFallback(pid, compactionFlags);
 }
 
-static void com_android_server_am_CachedAppOptimizer_enableFreezerInternal(
-        JNIEnv *env, jobject clazz, jboolean enable) {
-    bool success = true;
-
-    if (enable) {
-        success = SetTaskProfiles(0, {"FreezerEnabled"}, true);
-    } else {
-        success = SetTaskProfiles(0, {"FreezerDisabled"}, true);
-    }
-
-    if (!success) {
-        jniThrowException(env, "java/lang/RuntimeException", "Unknown error");
-    }
-}
-
 static void com_android_server_am_CachedAppOptimizer_freezeBinder(
         JNIEnv *env, jobject clazz, jint pid, jboolean freeze) {
 
@@ -280,15 +265,19 @@
 
 static jstring com_android_server_am_CachedAppOptimizer_getFreezerCheckPath(JNIEnv* env,
                                                                             jobject clazz) {
-    return env->NewStringUTF(CGROUP_FREEZE_PATH);
+    std::string path;
+
+    if (!getAttributePathForTask("FreezerState", getpid(), &path)) {
+        path = "";
+    }
+
+    return env->NewStringUTF(path.c_str());
 }
 
 static const JNINativeMethod sMethods[] = {
         /* name, signature, funcPtr */
         {"compactSystem", "()V", (void*)com_android_server_am_CachedAppOptimizer_compactSystem},
         {"compactProcess", "(II)V", (void*)com_android_server_am_CachedAppOptimizer_compactProcess},
-        {"enableFreezerInternal", "(Z)V",
-         (void*)com_android_server_am_CachedAppOptimizer_enableFreezerInternal},
         {"freezeBinder", "(IZ)V", (void*)com_android_server_am_CachedAppOptimizer_freezeBinder},
         {"getBinderFreezeInfo", "(I)I",
          (void*)com_android_server_am_CachedAppOptimizer_getBinderFreezeInfo},
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 21d57d8..10705af 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -331,7 +331,7 @@
                                           uint32_t policyFlags) override;
     bool dispatchUnhandledKey(const sp<IBinder>& token, const KeyEvent* keyEvent,
                               uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) override;
-    void pokeUserActivity(nsecs_t eventTime, int32_t eventType) override;
+    void pokeUserActivity(nsecs_t eventTime, int32_t eventType, int32_t displayId) override;
     bool checkInjectEventsPermissionNonReentrant(int32_t injectorPid, int32_t injectorUid) override;
     void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken) override;
     void setPointerCapture(bool enabled) override;
@@ -1325,9 +1325,9 @@
     return result;
 }
 
-void NativeInputManager::pokeUserActivity(nsecs_t eventTime, int32_t eventType) {
+void NativeInputManager::pokeUserActivity(nsecs_t eventTime, int32_t eventType, int32_t displayId) {
     ATRACE_CALL();
-    android_server_PowerManagerService_userActivity(eventTime, eventType);
+    android_server_PowerManagerService_userActivity(eventTime, eventType, displayId);
 }
 
 bool NativeInputManager::checkInjectEventsPermissionNonReentrant(
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index 63a6eed..9b7e27d 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -103,7 +103,8 @@
     return result == power::HalResult::SUCCESSFUL;
 }
 
-void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) {
+void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType,
+                                                     int32_t displayId) {
     if (gPowerManagerServiceObj) {
         // Throttle calls into user activity by event type.
         // We're a little conservative about argument checking here in case the caller
@@ -127,7 +128,7 @@
 
         env->CallVoidMethod(gPowerManagerServiceObj,
                 gPowerManagerServiceClassInfo.userActivityFromNative,
-                nanoseconds_to_milliseconds(eventTime), eventType, 0);
+                nanoseconds_to_milliseconds(eventTime), eventType, displayId, 0);
         checkAndClearExceptionFromCallback(env, "userActivityFromNative");
     }
 }
@@ -285,7 +286,7 @@
     FIND_CLASS(clazz, "com/android/server/power/PowerManagerService");
 
     GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivityFromNative, clazz,
-            "userActivityFromNative", "(JII)V");
+            "userActivityFromNative", "(JIII)V");
 
     // Initialize
     for (int i = 0; i <= USER_ACTIVITY_EVENT_LAST; i++) {
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.h b/services/core/jni/com_android_server_power_PowerManagerService.h
index a17fd65..a2f335c 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.h
+++ b/services/core/jni/com_android_server_power_PowerManagerService.h
@@ -24,7 +24,8 @@
 
 namespace android {
 
-extern void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType);
+extern void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType,
+                                                            int32_t displayId);
 
 } // namespace android
 
diff --git a/services/core/xsd/Android.bp b/services/core/xsd/Android.bp
index c285ef5..6a8f6d4 100644
--- a/services/core/xsd/Android.bp
+++ b/services/core/xsd/Android.bp
@@ -30,7 +30,6 @@
     gen_writer: true,
 }
 
-
 xsd_config {
     name: "display-device-config",
     srcs: ["display-device-config/display-device-config.xsd"],
@@ -38,6 +37,12 @@
     package_name: "com.android.server.display.config",
 }
 
+xsd_config {
+    name: "display-layout-config",
+    srcs: ["display-layout-config/display-layout-config.xsd"],
+    api_dir: "display-layout-config/schema",
+    package_name: "com.android.server.display.config.layout",
+}
 
 xsd_config {
     name: "cec-config",
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index 7d705c1..e4b9612 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -1,23 +1,24 @@
 <?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.
-  -->
+    Copyright (C) 2020 The Android Open Source Project
 
-<!-- This defines the format of the XML file generated by
-  ~ com.android.compat.annotation.ChangeIdProcessor annotation processor (from
-  ~ tools/platform-compat), and is parsed in com/android/server/compat/CompatConfig.java.
+    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.
+-->
+
+<!--
+    This defines the format of the XML file used to provide static configuration values
+    for the displays on a device.
+    It is parsed in com/android/server/display/DisplayDeviceConfig.java
 -->
 <xs:schema version="2.0"
            elementFormDefault="qualified"
diff --git a/services/core/xsd/display-layout-config/OWNERS b/services/core/xsd/display-layout-config/OWNERS
new file mode 100644
index 0000000..20b75be
--- /dev/null
+++ b/services/core/xsd/display-layout-config/OWNERS
@@ -0,0 +1,3 @@
+include /services/core/java/com/android/server/display/OWNERS
+
+flc@google.com
diff --git a/services/core/xsd/display-layout-config/display-layout-config.xsd b/services/core/xsd/display-layout-config/display-layout-config.xsd
new file mode 100644
index 0000000..c542c0d
--- /dev/null
+++ b/services/core/xsd/display-layout-config/display-layout-config.xsd
@@ -0,0 +1,57 @@
+<?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.
+-->
+
+<!--
+    This defines the format of the XML file used to defines how displays are laid out
+    for a given device-state.
+    It is parsed in com/android/server/display/layout/DeviceStateToLayoutMap.java
+    More information on device-state can be found in DeviceStateManager.java
+-->
+<xs:schema version="2.0"
+           elementFormDefault="qualified"
+           xmlns:xs="http://www.w3.org/2001/XMLSchema">
+    <xs:element name="layouts">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element type="layout" name="layout" minOccurs="1" maxOccurs="unbounded" />
+            </xs:sequence>
+        </xs:complexType>
+
+        <!-- Ensures only one layout is allowed per device state. -->
+        <xs:unique name="UniqueState">
+            <xs:selector xpath="layout" />
+            <xs:field xpath="@state" />
+        </xs:unique>
+    </xs:element>
+
+    <!-- Type definitions -->
+
+    <xs:complexType name="layout">
+        <xs:sequence>
+            <xs:element name="state" type="xs:nonNegativeInteger" />
+            <xs:element name="display" type="display" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="display">
+        <xs:sequence>
+            <xs:element name="address" type="xs:nonNegativeInteger"/>
+        </xs:sequence>
+        <xs:attribute name="enabled" type="xs:boolean" use="optional" />
+        <xs:attribute name="isDefault" type="xs:boolean" use="optional" />
+    </xs:complexType>
+</xs:schema>
diff --git a/services/core/xsd/display-layout-config/schema/current.txt b/services/core/xsd/display-layout-config/schema/current.txt
new file mode 100644
index 0000000..8171885
--- /dev/null
+++ b/services/core/xsd/display-layout-config/schema/current.txt
@@ -0,0 +1,34 @@
+// Signature format: 2.0
+package com.android.server.display.config.layout {
+
+  public class Display {
+    ctor public Display();
+    method public java.math.BigInteger getAddress();
+    method public boolean getEnabled();
+    method public boolean getIsDefault();
+    method public void setAddress(java.math.BigInteger);
+    method public void setEnabled(boolean);
+    method public void setIsDefault(boolean);
+  }
+
+  public class Layout {
+    ctor public Layout();
+    method public java.util.List<com.android.server.display.config.layout.Display> getDisplay();
+    method public java.math.BigInteger getState();
+    method public void setState(java.math.BigInteger);
+  }
+
+  public class Layouts {
+    ctor public Layouts();
+    method public java.util.List<com.android.server.display.config.layout.Layout> getLayout();
+  }
+
+  public class XmlParser {
+    ctor public XmlParser();
+    method public static com.android.server.display.config.layout.Layouts read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+  }
+
+}
+
diff --git a/services/core/xsd/display-layout-config/schema/last_current.txt b/services/core/xsd/display-layout-config/schema/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/services/core/xsd/display-layout-config/schema/last_current.txt
diff --git a/services/core/xsd/display-layout-config/schema/last_removed.txt b/services/core/xsd/display-layout-config/schema/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/services/core/xsd/display-layout-config/schema/last_removed.txt
diff --git a/services/core/xsd/display-layout-config/schema/removed.txt b/services/core/xsd/display-layout-config/schema/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/services/core/xsd/display-layout-config/schema/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index b52347f..ef7afc8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -129,6 +129,15 @@
             FullyManagedDeviceProvisioningParams provisioningParams, String callerPackage) {
     }
 
+    @Override
+    public void setDeviceOwnerType(@NonNull ComponentName admin, int deviceOwnerType) {
+    }
+
+    @Override
+    public int getDeviceOwnerType(@NonNull ComponentName admin) {
+        return 0;
+    }
+
     public void resetDefaultCrossProfileIntentFilters(@UserIdInt int userId) {}
 
     public boolean canAdminGrantSensorsPermissionsForUser(int userId) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 6857a68..28e9acf 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -156,6 +156,7 @@
 import android.app.admin.DevicePolicyCache;
 import android.app.admin.DevicePolicyEventLogger;
 import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManager.DeviceOwnerType;
 import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
 import android.app.admin.DevicePolicyManager.OperationSafetyReason;
 import android.app.admin.DevicePolicyManager.PasswordComplexity;
@@ -714,6 +715,9 @@
     @Nullable
     private DevicePolicySafetyChecker mSafetyChecker;
 
+    @GuardedBy("getLockObject()")
+    private final ArrayList<Object> mPendingUserCreatedCallbackTokens = new ArrayList<>();
+
     public static final class Lifecycle extends SystemService {
         private BaseIDevicePolicyManager mService;
 
@@ -752,21 +756,25 @@
 
         @Override
         public void onUserStarting(@NonNull TargetUser user) {
+            if (user.isPreCreated()) return;
             mService.handleStartUser(user.getUserIdentifier());
         }
 
         @Override
         public void onUserUnlocking(@NonNull TargetUser user) {
+            if (user.isPreCreated()) return;
             mService.handleUnlockUser(user.getUserIdentifier());
         }
 
         @Override
         public void onUserStopping(@NonNull TargetUser user) {
+            if (user.isPreCreated()) return;
             mService.handleStopUser(user.getUserIdentifier());
         }
 
         @Override
         public void onUserUnlocked(@NonNull TargetUser user) {
+            if (user.isPreCreated()) return;
             mService.handleOnUserUnlocked(user.getUserIdentifier());
         }
     }
@@ -964,8 +972,8 @@
     private final class UserLifecycleListener implements UserManagerInternal.UserLifecycleListener {
 
         @Override
-        public void onUserCreated(UserInfo user) {
-            mHandler.post(() -> handleNewUserCreated(user));
+        public void onUserCreated(UserInfo user, Object token) {
+            mHandler.post(() -> handleNewUserCreated(user, token));
         }
     }
 
@@ -3150,11 +3158,6 @@
         if (!mHasFeature) {
             return;
         }
-        setActiveAdmin(adminReceiver, refreshing, userHandle, null);
-    }
-
-    private void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle,
-            Bundle onEnableData) {
         Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
 
         final CallerIdentity caller = getCallerIdentity();
@@ -3197,7 +3200,7 @@
                 }
                 saveSettingsLocked(userHandle);
                 sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
-                        onEnableData, null);
+                        /* adminExtras= */ null, /* result= */ null);
             });
         }
     }
@@ -3403,8 +3406,10 @@
             return;
         }
         Objects.requireNonNull(adminReceiver, "ComponentName is null");
-        Preconditions.checkCallAuthorization(isAdb(getCallerIdentity()),
-                "Non-shell user attempted to call forceRemoveActiveAdmin");
+        Preconditions.checkCallAuthorization(isAdb(getCallerIdentity())
+                        || hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS),
+                "Caller must be shell or hold MANAGE_PROFILE_AND_DEVICE_OWNERS to call "
+                        + "forceRemoveActiveAdmin");
         mInjector.binderWithCleanCallingIdentity(() -> {
             synchronized (getLockObject()) {
                 if (!isAdminTestOnlyLocked(adminReceiver, userHandle)) {
@@ -7581,8 +7586,7 @@
     }
 
     private void sendProfileOwnerCommand(String action, Bundle extras, @UserIdInt int userId) {
-        sendActiveAdminCommand(action, extras, userId,
-                mOwners.getProfileOwnerComponent(userId));
+        sendActiveAdminCommand(action, extras, userId, mOwners.getProfileOwnerComponent(userId));
     }
 
     private void sendActiveAdminCommand(String action, Bundle extras,
@@ -8110,7 +8114,8 @@
             return null;
         }
         if (!callingUserOnly) {
-            Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity()));
+            Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity())
+                    || hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
         }
         synchronized (getLockObject()) {
             if (!mOwners.hasDeviceOwner()) {
@@ -9184,13 +9189,24 @@
                 pw.println();
                 mStatLogger.dump(pw);
                 pw.println();
-
                 pw.println("Encryption Status: " + getEncryptionStatusName(getEncryptionStatus()));
                 pw.println();
+
+                if (mPendingUserCreatedCallbackTokens.isEmpty()) {
+                    pw.println("no pending user created callback tokens");
+                } else {
+                    int size = mPendingUserCreatedCallbackTokens.size();
+                    pw.printf("%d pending user created callback token%s\n", size,
+                            (size == 1 ? "" : "s"));
+                }
+                pw.println();
+
                 mPolicyCache.dump(pw);
                 pw.println();
                 mStateCache.dump(pw);
+                pw.println();
             }
+            dumpResources(pw);
         }
     }
 
@@ -9205,6 +9221,32 @@
         pw.decreaseIndent();
     }
 
+    private void dumpResources(IndentingPrintWriter pw) {
+        mOverlayPackagesProvider.dump(pw);
+        pw.println();
+
+        pw.println("Other overlayable app resources");
+        pw.increaseIndent();
+        dumpResources(pw, mContext, "cross_profile_apps", R.array.cross_profile_apps);
+        dumpResources(pw, mContext, "vendor_cross_profile_apps", R.array.vendor_cross_profile_apps);
+        pw.decreaseIndent();
+        pw.println();
+    }
+
+    static void dumpResources(IndentingPrintWriter pw, Context context, String resName, int resId) {
+        String[] apps = context.getResources().getStringArray(resId);
+        if (apps == null || apps.length == 0) {
+            pw.printf("%s: empty\n", resName);
+            return;
+        }
+        pw.printf("%s: %d app%s\n", resName, apps.length, apps.length == 1 ? "" : "s");
+        pw.increaseIndent();
+        for (int i = 0; i < apps.length; i++) {
+            pw.printf("%d: %s\n", i, apps[i]);
+        }
+        pw.decreaseIndent();
+    }
+
     @Override
     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
             String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
@@ -9943,8 +9985,8 @@
                 clearInitBundle = sendAdminCommandLocked(admin,
                         DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
                         initBundle == null ? null : new Bundle(initBundle),
-                        null /* result receiver */,
-                        true /* send in foreground */);
+                        /* result= */ null ,
+                        /* inForeground= */ true);
             }
             if (clearInitBundle) {
                 // If there's no admin or we've successfully called the admin, clear the init bundle
@@ -10017,9 +10059,13 @@
                             UserHandle.myUserId(), ACTION_PROVISION_MANAGED_USER).toArray(
                             new String[0]);
                 }
+
+                Object token = new Object();
+                Slog.d(LOG_TAG, "Adding new pending token: " + token);
+                mPendingUserCreatedCallbackTokens.add(token);
                 try {
                     UserInfo userInfo = mUserManagerInternal.createUserEvenWhenDisallowed(name,
-                            userType, userInfoFlags, disallowedPackages);
+                            userType, userInfoFlags, disallowedPackages, token);
                     if (userInfo != null) {
                         user = userInfo.getUserHandle();
                     }
@@ -10029,7 +10075,8 @@
             } finally {
                 mInjector.binderRestoreCallingIdentity(id);
             }
-        }
+        } // synchronized
+
         if (user == null) {
             if (targetSdkVersion >= Build.VERSION_CODES.P) {
                 throw new ServiceSpecificException(UserManager.USER_OPERATION_ERROR_UNKNOWN,
@@ -10051,14 +10098,8 @@
 
         final long id = mInjector.binderClearCallingIdentity();
         try {
-            if (!mInjector.userManagerIsHeadlessSystemUserMode()) {
-                manageUserUnchecked(admin, profileOwner, userHandle, adminExtras,
-                        /* showDisclaimer= */ true);
-            } else if (VERBOSE_LOG) {
-                Slog.v(LOG_TAG, "createAndManageUser(): skipping manageUserUnchecked() on user "
-                        + userHandle + " on headless system user as it will be called by "
-                                + "handleNewUserCreated()");
-            }
+            manageUserUnchecked(admin, profileOwner, userHandle, adminExtras,
+                    /* showDisclaimer= */ true);
 
             if ((flags & DevicePolicyManager.SKIP_SETUP_WIZARD) != 0) {
                 Settings.Secure.putIntForUser(mContext.getContentResolver(),
@@ -10080,7 +10121,15 @@
     }
 
     private void manageUserUnchecked(ComponentName admin, ComponentName profileOwner,
-            @UserIdInt int userId, PersistableBundle adminExtras, boolean showDisclaimer) {
+            @UserIdInt int userId, @Nullable PersistableBundle adminExtras,
+            boolean showDisclaimer) {
+        synchronized (getLockObject()) {
+            if (VERBOSE_LOG) {
+                Slog.v(LOG_TAG, "manageUserUnchecked(): admin=" + admin + ", po=" + profileOwner
+                        + ", userId=" + userId + ", hasAdminExtras=" + (adminExtras != null)
+                        + ", showDisclaimer=" + showDisclaimer);
+            }
+        }
         final String adminPkg = admin.getPackageName();
         try {
             // Install the profile owner if not present.
@@ -10110,23 +10159,37 @@
                     ? DevicePolicyData.NEW_USER_DISCLAIMER_NEEDED
                     : DevicePolicyData.NEW_USER_DISCLAIMER_NOT_NEEDED;
             saveSettingsLocked(userId);
+
         }
     }
 
-    private void handleNewUserCreated(UserInfo user) {
-        if (VERBOSE_LOG) Slog.v(LOG_TAG, "handleNewUserCreated(): " + user.toFullString());
-
-        if (!mOwners.hasDeviceOwner() || !user.isFull() || user.isManagedProfile()) return;
+    private void handleNewUserCreated(UserInfo user, @Nullable Object token) {
+        if (VERBOSE_LOG) {
+            Slog.v(LOG_TAG, "handleNewUserCreated(): user=" + user.toFullString()
+                    + ", token=" + token);
+        }
 
         final int userId = user.id;
+        if (token != null) {
+            synchronized (getLockObject()) {
+                if (mPendingUserCreatedCallbackTokens.contains(token)) {
+                    // Ignore because it was triggered by createAndManageUser()
+                    Slog.d(LOG_TAG, "handleNewUserCreated(): ignoring for user " + userId
+                            + " due to token" + token);
+                    mPendingUserCreatedCallbackTokens.remove(token);
+                    return;
+                }
+            }
+        }
+
+        if (!mOwners.hasDeviceOwner() || !user.isFull() || user.isManagedProfile()) return;
 
         if (mInjector.userManagerIsHeadlessSystemUserMode()) {
             ComponentName admin = mOwners.getDeviceOwnerComponent();
             Slog.i(LOG_TAG, "Automatically setting profile owner (" + admin + ") on new user "
                     + userId);
             manageUserUnchecked(/* deviceOwner= */ admin, /* profileOwner= */ admin,
-                    /* managedUser= */ userId, /* adminExtras= */ null,
-                    /* showDisclaimer= */ true);
+                    /* managedUser= */ userId, /* adminExtras= */ null, /* showDisclaimer= */ true);
         } else {
             Log.i(LOG_TAG, "User " + userId + " added on DO mode; setting ShowNewUserDisclaimer");
             setShowNewUserDisclaimer(userId, DevicePolicyData.NEW_USER_DISCLAIMER_NEEDED);
@@ -10247,11 +10310,12 @@
         final long id = mInjector.binderClearCallingIdentity();
         try {
             if (!mInjector.getActivityManagerInternal().canStartMoreUsers()) {
-                Log.w(LOG_TAG, "Cannot start more users in background");
+                Log.w(LOG_TAG, "Cannot start user " + userId + ", too many users in background");
                 return UserManager.USER_OPERATION_ERROR_MAX_RUNNING_USERS;
             }
 
             if (mInjector.getIActivityManager().startUserInBackground(userId)) {
+                Log.i(LOG_TAG, "Started used " + userId + " in background");
                 return UserManager.USER_OPERATION_SUCCESS;
             } else {
                 return UserManager.USER_OPERATION_ERROR_UNKNOWN;
@@ -12372,8 +12436,10 @@
             extras.putInt(DeviceAdminReceiver.EXTRA_OPERATION_SAFETY_REASON, reason);
             extras.putBoolean(DeviceAdminReceiver.EXTRA_OPERATION_SAFETY_STATE, isSafe);
 
-            sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_OPERATION_SAFETY_STATE_CHANGED,
-                    extras);
+            if (mOwners.hasDeviceOwner()) {
+                sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_OPERATION_SAFETY_STATE_CHANGED,
+                        extras);
+            }
             for (int profileOwnerId : mOwners.getProfileOwnerKeys()) {
                 sendProfileOwnerCommand(DeviceAdminReceiver.ACTION_OPERATION_SAFETY_STATE_CHANGED,
                         extras, profileOwnerId);
@@ -12564,8 +12630,10 @@
 
     @Override
     public void clearSystemUpdatePolicyFreezePeriodRecord() {
-        Preconditions.checkCallAuthorization(isAdb(getCallerIdentity()),
-                "Non-shell user attempted to call clearSystemUpdatePolicyFreezePeriodRecord");
+        Preconditions.checkCallAuthorization(isAdb(getCallerIdentity())
+                        || hasCallingOrSelfPermission(permission.CLEAR_FREEZE_PERIOD),
+                "Caller must be shell, or hold CLEAR_FREEZE_PERIOD permission to call "
+                        + "clearSystemUpdatePolicyFreezePeriodRecord");
         synchronized (getLockObject()) {
             // Print out current record to help diagnosed CTS failures
             Slog.i(LOG_TAG, "Clear freeze period record: "
@@ -13508,7 +13576,8 @@
         final CallerIdentity caller = getCallerIdentity();
         // Only adb or system apps with the right permission can mark a profile owner on
         // organization-owned device.
-        if (!(isAdb(caller) || hasCallingPermission(permission.MARK_DEVICE_ORGANIZATION_OWNED))) {
+        if (!(isAdb(caller) || hasCallingPermission(permission.MARK_DEVICE_ORGANIZATION_OWNED)
+                || hasCallingPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS))) {
             throw new SecurityException(
                     "Only the system can mark a profile owner of organization-owned device.");
         }
@@ -13827,8 +13896,10 @@
 
     @Override
     public long forceSecurityLogs() {
-        Preconditions.checkCallAuthorization(isAdb(getCallerIdentity()),
-                "Non-shell user attempted to call forceSecurityLogs");
+        Preconditions.checkCallAuthorization(isAdb(getCallerIdentity())
+                        || hasCallingOrSelfPermission(permission.FORCE_DEVICE_POLICY_MANAGER_LOGS),
+                "Caller must be shell or hold FORCE_DEVICE_POLICY_MANAGER_LOGS to call "
+                        + "forceSecurityLogs");
         if (!mInjector.securityLogGetLoggingEnabledProperty()) {
             throw new IllegalStateException("logging is not available");
         }
@@ -14348,8 +14419,10 @@
 
     @Override
     public long forceNetworkLogs() {
-        Preconditions.checkCallAuthorization(isAdb(getCallerIdentity()),
-                "Non-shell user attempted to call forceNetworkLogs");
+        Preconditions.checkCallAuthorization(isAdb(getCallerIdentity())
+                || hasCallingOrSelfPermission(permission.FORCE_DEVICE_POLICY_MANAGER_LOGS),
+                "Caller must be shell or hold FORCE_DEVICE_POLICY_MANAGER_LOGS to call "
+                        + "forceNetworkLogs");
         synchronized (getLockObject()) {
             if (!isNetworkLoggingEnabledInternalLocked()) {
                 throw new IllegalStateException("logging is not available");
@@ -16752,6 +16825,37 @@
     }
 
     @Override
+    public void setDeviceOwnerType(@NonNull ComponentName admin,
+            @DeviceOwnerType int deviceOwnerType) {
+        Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
+                permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
+        verifyDeviceOwnerTypePreconditions(admin);
+
+        final String packageName = admin.getPackageName();
+        Preconditions.checkState(!mOwners.isDeviceOwnerTypeSetForDeviceOwner(packageName),
+                "The device owner type has already been set for " + packageName);
+
+        synchronized (getLockObject()) {
+            mOwners.setDeviceOwnerType(packageName, deviceOwnerType);
+        }
+    }
+
+    @Override
+    @DeviceOwnerType
+    public int getDeviceOwnerType(@NonNull ComponentName admin) {
+        verifyDeviceOwnerTypePreconditions(admin);
+        synchronized (getLockObject()) {
+            return mOwners.getDeviceOwnerType(admin.getPackageName());
+        }
+    }
+
+    private void verifyDeviceOwnerTypePreconditions(@NonNull ComponentName admin) {
+        Preconditions.checkState(mOwners.hasDeviceOwner(), "there is no device owner");
+        Preconditions.checkState(mOwners.getDeviceOwnerComponent().equals(admin),
+                "admin is not the device owner");
+    }
+
+    @Override
     public void setUsbDataSignalingEnabled(String packageName, boolean enabled) {
         Objects.requireNonNull(packageName, "Admin package name must be provided");
         final CallerIdentity caller = getCallerIdentity(packageName);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java b/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java
index 776b444..257fc64 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java
@@ -23,6 +23,8 @@
 import android.app.admin.DevicePolicyManager.OperationSafetyReason;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.app.admin.DevicePolicySafetyChecker;
+import android.os.Handler;
+import android.os.Looper;
 import android.util.Slog;
 
 import com.android.internal.os.IResultReceiver;
@@ -42,10 +44,15 @@
 
     private static final String TAG = OneTimeSafetyChecker.class.getSimpleName();
 
+    private static final long SELF_DESTRUCT_TIMEOUT_MS = 10_000;
+
     private final DevicePolicyManagerService mService;
     private final DevicePolicySafetyChecker mRealSafetyChecker;
     private final @DevicePolicyOperation int mOperation;
     private final @OperationSafetyReason int mReason;
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
+
+    private boolean mDone;
 
     OneTimeSafetyChecker(DevicePolicyManagerService service,
             @DevicePolicyOperation int operation, @OperationSafetyReason int reason) {
@@ -53,7 +60,11 @@
         mOperation = operation;
         mReason = reason;
         mRealSafetyChecker = service.getDevicePolicySafetyChecker();
-        Slog.i(TAG, "Saving real DevicePolicySafetyChecker as " + mRealSafetyChecker);
+        Slog.i(TAG, "OneTimeSafetyChecker constructor: operation= " + operationToString(operation)
+                + ", reason=" + operationSafetyReasonToString(reason)
+                + ", realChecker=" + mRealSafetyChecker
+                + ", maxDuration=" + SELF_DESTRUCT_TIMEOUT_MS + "ms");
+        mHandler.postDelayed(() -> selfDestruct(), SELF_DESTRUCT_TIMEOUT_MS);
     }
 
     @Override
@@ -99,8 +110,21 @@
     }
 
     private void disableSelf() {
+        if (mDone) {
+            Slog.w(TAG, "disableSelf(): already disabled");
+            return;
+        }
         Slog.i(TAG, "restoring DevicePolicySafetyChecker to " + mRealSafetyChecker);
         mService.setDevicePolicySafetyCheckerUnchecked(mRealSafetyChecker);
+        mDone = true;
+    }
+
+    private void selfDestruct() {
+        if (mDone) return;
+
+        // Usually happens when a CTS failed before calling the DPM method that would clear it
+        Slog.e(TAG, "Self destructing " + this + ", as it was not automatically disabled");
+        disableSelf();
     }
 
     @Override
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java
index 261a83c..280f12f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java
@@ -21,6 +21,7 @@
 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
 
 import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.server.devicepolicy.DevicePolicyManagerService.dumpResources;
 
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
@@ -32,6 +33,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.util.ArraySet;
+import android.util.IndentingPrintWriter;
 import android.view.inputmethod.InputMethodInfo;
 
 import com.android.internal.R;
@@ -224,4 +226,39 @@
         }
         return new ArraySet<>(Arrays.asList(mContext.getResources().getStringArray(resId)));
     }
+
+    void dump(IndentingPrintWriter pw) {
+        pw.println("OverlayPackagesProvider");
+        pw.increaseIndent();
+
+        dumpResources(pw, mContext, "required_apps_managed_device",
+                R.array.required_apps_managed_device);
+        dumpResources(pw, mContext, "required_apps_managed_user",
+                R.array.required_apps_managed_user);
+        dumpResources(pw, mContext, "required_apps_managed_profile",
+                R.array.required_apps_managed_profile);
+
+        dumpResources(pw, mContext, "disallowed_apps_managed_device",
+                R.array.disallowed_apps_managed_device);
+        dumpResources(pw, mContext, "disallowed_apps_managed_user",
+                R.array.disallowed_apps_managed_user);
+        dumpResources(pw, mContext, "disallowed_apps_managed_device",
+                R.array.disallowed_apps_managed_device);
+
+        dumpResources(pw, mContext, "vendor_required_apps_managed_device",
+                R.array.vendor_required_apps_managed_device);
+        dumpResources(pw, mContext, "vendor_required_apps_managed_user",
+                R.array.vendor_required_apps_managed_user);
+        dumpResources(pw, mContext, "vendor_required_apps_managed_profile",
+                R.array.vendor_required_apps_managed_profile);
+
+        dumpResources(pw, mContext, "vendor_disallowed_apps_managed_user",
+                R.array.vendor_disallowed_apps_managed_user);
+        dumpResources(pw, mContext, "vendor_disallowed_apps_managed_device",
+                R.array.vendor_disallowed_apps_managed_device);
+        dumpResources(pw, mContext, "vendor_disallowed_apps_managed_profile",
+                R.array.vendor_disallowed_apps_managed_profile);
+
+        pw.decreaseIndent();
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 1e70d59..7fdd6ee 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -16,10 +16,13 @@
 
 package com.android.server.devicepolicy;
 
+import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
+
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManagerInternal;
 import android.app.AppOpsManagerInternal;
+import android.app.admin.DevicePolicyManager.DeviceOwnerType;
 import android.app.admin.SystemUpdateInfo;
 import android.app.admin.SystemUpdatePolicy;
 import android.content.ComponentName;
@@ -93,6 +96,7 @@
     private static final String TAG_PROFILE_OWNER = "profile-owner";
     // Holds "context" for device-owner, this must not be show up before device-owner.
     private static final String TAG_DEVICE_OWNER_CONTEXT = "device-owner-context";
+    private static final String TAG_DEVICE_OWNER_TYPE = "device-owner-type";
 
     private static final String ATTR_NAME = "name";
     private static final String ATTR_PACKAGE = "package";
@@ -109,6 +113,7 @@
     // New attribute for profile owner of organization-owned device.
     private static final String ATTR_PROFILE_OWNER_OF_ORG_OWNED_DEVICE =
             "isPoOrganizationOwnedDevice";
+    private static final String ATTR_DEVICE_OWNER_TYPE_VALUE = "value";
 
     private final UserManager mUserManager;
     private final UserManagerInternal mUserManagerInternal;
@@ -121,6 +126,9 @@
     // Internal state for the device owner package.
     private OwnerInfo mDeviceOwner;
 
+    // Device owner type for a managed device.
+    private final ArrayMap<String, Integer> mDeviceOwnerTypes = new ArrayMap<>();
+
     private int mDeviceOwnerUserId = UserHandle.USER_NULL;
 
     // Internal state for the profile owner packages.
@@ -334,6 +342,7 @@
 
     void clearDeviceOwner() {
         synchronized (mLock) {
+            mDeviceOwnerTypes.remove(mDeviceOwner.packageName);
             mDeviceOwner = null;
             mDeviceOwnerUserId = UserHandle.USER_NULL;
 
@@ -384,12 +393,16 @@
 
     void transferDeviceOwnership(ComponentName target) {
         synchronized (mLock) {
+            Integer previousDeviceOwnerType = mDeviceOwnerTypes.remove(mDeviceOwner.packageName);
             // We don't set a name because it's not used anyway.
             // See DevicePolicyManagerService#getDeviceOwnerName
             mDeviceOwner = new OwnerInfo(null, target,
                     mDeviceOwner.userRestrictionsMigrated, mDeviceOwner.remoteBugreportUri,
                     mDeviceOwner.remoteBugreportHash, /* isOrganizationOwnedDevice =*/
                     mDeviceOwner.isOrganizationOwnedDevice);
+            if (previousDeviceOwnerType != null) {
+                mDeviceOwnerTypes.put(mDeviceOwner.packageName, previousDeviceOwnerType);
+            }
             pushToPackageManagerLocked();
             pushToActivityTaskManagerLocked();
             pushToActivityManagerLocked();
@@ -596,6 +609,37 @@
         }
     }
 
+    void setDeviceOwnerType(String packageName, @DeviceOwnerType int deviceOwnerType) {
+        synchronized (mLock) {
+            if (!hasDeviceOwner()) {
+                Slog.e(TAG, "Attempting to set a device owner type when there is no device owner");
+                return;
+            } else if (isDeviceOwnerTypeSetForDeviceOwner(packageName)) {
+                Slog.e(TAG, "Device owner type for " + packageName + " has already been set");
+                return;
+            }
+
+            mDeviceOwnerTypes.put(packageName, deviceOwnerType);
+            writeDeviceOwner();
+        }
+    }
+
+    @DeviceOwnerType
+    int getDeviceOwnerType(String packageName) {
+        synchronized (mLock) {
+            if (isDeviceOwnerTypeSetForDeviceOwner(packageName)) {
+                return mDeviceOwnerTypes.get(packageName);
+            }
+            return DEVICE_OWNER_TYPE_DEFAULT;
+        }
+    }
+
+    boolean isDeviceOwnerTypeSetForDeviceOwner(String packageName) {
+        synchronized (mLock) {
+            return !mDeviceOwnerTypes.isEmpty() && mDeviceOwnerTypes.containsKey(packageName);
+        }
+    }
+
     private boolean readLegacyOwnerFileLocked(File file) {
         if (!file.exists()) {
             // Already migrated or the device has no owners.
@@ -880,6 +924,16 @@
                 out.startTag(null, TAG_DEVICE_OWNER_CONTEXT);
                 out.attributeInt(null, ATTR_USERID, mDeviceOwnerUserId);
                 out.endTag(null, TAG_DEVICE_OWNER_CONTEXT);
+
+            }
+
+            if (!mDeviceOwnerTypes.isEmpty()) {
+                for (ArrayMap.Entry<String, Integer> entry : mDeviceOwnerTypes.entrySet()) {
+                    out.startTag(null, TAG_DEVICE_OWNER_TYPE);
+                    out.attribute(null, ATTR_PACKAGE, entry.getKey());
+                    out.attributeInt(null, ATTR_DEVICE_OWNER_TYPE_VALUE, entry.getValue());
+                    out.endTag(null, TAG_DEVICE_OWNER_TYPE);
+                }
             }
 
             if (mSystemUpdatePolicy != null) {
@@ -942,6 +996,12 @@
                         }
                     }
                     break;
+                case TAG_DEVICE_OWNER_TYPE:
+                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+                    int deviceOwnerType = parser.getAttributeInt(null, ATTR_DEVICE_OWNER_TYPE_VALUE,
+                            DEVICE_OWNER_TYPE_DEFAULT);
+                    mDeviceOwnerTypes.put(packageName, deviceOwnerType);
+                    break;
                 default:
                     Slog.e(TAG, "Unexpected tag: " + tag);
                     return false;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index d50db91a..a3d3353 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -162,6 +162,7 @@
 import com.android.server.pm.UserManagerService;
 import com.android.server.pm.dex.SystemServerDexLoadReporter;
 import com.android.server.pm.verify.domain.DomainVerificationService;
+import com.android.server.policy.AppOpsPolicy;
 import com.android.server.policy.PermissionPolicyService;
 import com.android.server.policy.PhoneWindowManager;
 import com.android.server.policy.role.RoleServicePlatformHelperImpl;
@@ -1717,14 +1718,9 @@
             startTextToSpeechManagerService(context, t);
 
             // System Speech Recognition Service
-            if (deviceHasConfigString(context,
-                    R.string.config_defaultOnDeviceSpeechRecognitionService)) {
-                t.traceBegin("StartSpeechRecognitionManagerService");
-                mSystemServiceManager.startService(SPEECH_RECOGNITION_MANAGER_SERVICE_CLASS);
-                t.traceEnd();
-            } else {
-                Slog.d(TAG, "System speech recognition is not defined by OEM");
-            }
+            t.traceBegin("StartSpeechRecognitionManagerService");
+            mSystemServiceManager.startService(SPEECH_RECOGNITION_MANAGER_SERVICE_CLASS);
+            t.traceEnd();
 
             // App prediction manager service
             if (deviceHasConfigString(context, R.string.config_defaultAppPredictionService)) {
@@ -2661,6 +2657,14 @@
             }
             t.traceEnd();
 
+            t.traceBegin("RegisterAppOpsPolicy");
+            try {
+                mActivityManagerService.setAppOpsPolicy(new AppOpsPolicy());
+            } catch (Throwable e) {
+                reportWtf("registering app ops policy", e);
+            }
+            t.traceEnd();
+
             // No dependency on Webview preparation in system server. But this should
             // be completed before allowing 3rd party
             final String WEBVIEW_PREPARATION = "WebViewFactoryPreparation";
diff --git a/services/musicrecognition/Android.bp b/services/musicrecognition/Android.bp
index fea9efa..8298dec 100644
--- a/services/musicrecognition/Android.bp
+++ b/services/musicrecognition/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 filegroup {
     name: "services.musicsearch-sources",
     srcs: ["java/**/*.java"],
@@ -10,4 +19,4 @@
     defaults: ["platform_service_defaults"],
     srcs: [":services.musicsearch-sources"],
     libs: ["services.core", "app-compat-annotations"],
-}
\ No newline at end of file
+}
diff --git a/services/net/Android.bp b/services/net/Android.bp
index c68004a..b01e425 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -52,6 +52,7 @@
     libs: [
         "unsupportedappusage",
         "framework-wifi-util-lib",
+        "framework-connectivity"
     ],
     static_libs: [
         // All the classes in netd_aidl_interface must be jarjar so they do not conflict with the
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index 0d878b4..a262939 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -102,7 +102,7 @@
             return false;
         }
         try {
-            return !mIProfcollect.GetSupportedProvider().isEmpty();
+            return !mIProfcollect.get_supported_provider().isEmpty();
         } catch (RemoteException e) {
             Log.e(LOG_TAG, e.getMessage());
             return false;
@@ -191,7 +191,7 @@
             }
 
             try {
-                sSelfService.mIProfcollect.ProcessProfile();
+                sSelfService.mIProfcollect.process(false);
             } catch (RemoteException e) {
                 Log.e(LOG_TAG, e.getMessage());
             }
@@ -234,7 +234,7 @@
                 if (DEBUG) {
                     Log.d(LOG_TAG, "Tracing on app launch event: " + packageName);
                 }
-                mIProfcollect.TraceOnce("applaunch");
+                mIProfcollect.trace_once("applaunch");
             } catch (RemoteException e) {
                 Log.e(LOG_TAG, e.getMessage());
             }
@@ -296,7 +296,7 @@
         }
 
         try {
-            mIProfcollect.CreateProfileReport();
+            mIProfcollect.report();
         } catch (RemoteException e) {
             Log.e(LOG_TAG, e.getMessage());
         }
diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
index cbebe69..2219d47 100644
--- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java
@@ -38,7 +38,6 @@
 
 import android.annotation.UserIdInt;
 import android.app.Application;
-import android.app.backup.BackupManager.OperationType;
 import android.app.backup.IBackupManagerMonitor;
 import android.app.backup.IBackupObserver;
 import android.app.backup.IFullBackupRestoreObserver;
@@ -874,8 +873,7 @@
                 SecurityException.class,
                 () ->
                         backupManagerService.requestBackup(
-                                mUserTwoId, packages, observer, monitor, 0,
-                                OperationType.BACKUP));
+                                mUserTwoId, packages, observer, monitor, 0));
     }
 
     /**
@@ -893,11 +891,9 @@
         IBackupManagerMonitor monitor = mock(IBackupManagerMonitor.class);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ true);
 
-        backupManagerService.requestBackup(mUserTwoId, packages, observer, monitor, /* flags */ 0,
-                OperationType.BACKUP);
+        backupManagerService.requestBackup(mUserTwoId, packages, observer, monitor, /* flags */ 0);
 
-        verify(mUserTwoService).requestBackup(packages, observer, monitor, /* flags */ 0,
-                OperationType.BACKUP);
+        verify(mUserTwoService).requestBackup(packages, observer, monitor, /* flags */ 0);
     }
 
     /** Test that the backup service routes methods correctly to the user that requests it. */
@@ -910,11 +906,9 @@
         IBackupManagerMonitor monitor = mock(IBackupManagerMonitor.class);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
-        backupManagerService.requestBackup(mUserOneId, packages, observer, monitor, /* flags */ 0,
-                OperationType.BACKUP);
+        backupManagerService.requestBackup(mUserOneId, packages, observer, monitor, /* flags */ 0);
 
-        verify(mUserOneService).requestBackup(packages, observer, monitor, /* flags */ 0,
-                OperationType.BACKUP);
+        verify(mUserOneService).requestBackup(packages, observer, monitor, /* flags */ 0);
     }
 
     /** Test that the backup service routes methods correctly to the user that requests it. */
@@ -927,11 +921,9 @@
         IBackupManagerMonitor monitor = mock(IBackupManagerMonitor.class);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
-        backupManagerService.requestBackup(mUserTwoId, packages, observer, monitor, /* flags */ 0,
-                OperationType.BACKUP);
+        backupManagerService.requestBackup(mUserTwoId, packages, observer, monitor, /* flags */ 0);
 
-        verify(mUserOneService, never()).requestBackup(packages, observer, monitor, /* flags */ 0,
-                OperationType.BACKUP);
+        verify(mUserOneService, never()).requestBackup(packages, observer, monitor, /* flags */ 0);
     }
 
     /**
@@ -1092,11 +1084,9 @@
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
-        backupManagerService.beginRestoreSession(mUserOneId, TEST_PACKAGE, TEST_TRANSPORT,
-                OperationType.BACKUP);
+        backupManagerService.beginRestoreSession(mUserOneId, TEST_PACKAGE, TEST_TRANSPORT);
 
-        verify(mUserOneService).beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT,
-                OperationType.BACKUP);
+        verify(mUserOneService).beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT);
     }
 
     /** Test that the backup service does not route methods for non-registered users. */
@@ -1106,11 +1096,9 @@
         registerUser(backupManagerService, mUserOneId, mUserOneService);
         setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
-        backupManagerService.beginRestoreSession(mUserTwoId, TEST_PACKAGE, TEST_TRANSPORT,
-                OperationType.BACKUP);
+        backupManagerService.beginRestoreSession(mUserTwoId, TEST_PACKAGE, TEST_TRANSPORT);
 
-        verify(mUserOneService, never()).beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT,
-                OperationType.BACKUP);
+        verify(mUserOneService, never()).beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT);
     }
 
     /** Test that the backup service routes methods correctly to the user that requests it. */
diff --git a/services/searchui/Android.bp b/services/searchui/Android.bp
index cc63294..3081a51 100644
--- a/services/searchui/Android.bp
+++ b/services/searchui/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 filegroup {
     name: "services.searchui-sources",
     srcs: ["java/**/*.java"],
diff --git a/services/smartspace/Android.bp b/services/smartspace/Android.bp
index fcf780d..640a88d 100644
--- a/services/smartspace/Android.bp
+++ b/services/smartspace/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 filegroup {
     name: "services.smartspace-sources",
     srcs: ["java/**/*.java"],
diff --git a/services/tests/PackageManagerServiceTests/host/libs/IntentVerifyUtils/Android.bp b/services/tests/PackageManagerServiceTests/host/libs/IntentVerifyUtils/Android.bp
index b7a0624..e70a734 100644
--- a/services/tests/PackageManagerServiceTests/host/libs/IntentVerifyUtils/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/libs/IntentVerifyUtils/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 java_library {
     name: "PackageManagerServiceHostTestsIntentVerifyUtils",
     srcs: ["src/**/*.kt"],
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
index af0ac77..7e4f0e7 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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_test_helper_app {
     name: "PackageManagerServiceDeviceSideTests",
     sdk_version: "test_current",
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/Android.bp
index e82f57d..4f3f2eb 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+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_test_helper_app {
     name: "PackageManagerTestIntentVerifier",
     srcs: [ "src/**/*.kt" ],
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/Android.bp
index 7161fdd..9f9ed24 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+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_test_helper_app {
     name: "PackageManagerTestIntentVerifierTarget1",
     manifest: "AndroidManifest1.xml",
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/Android.bp
index 58f17f2..ebad5af 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+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_test_helper_app {
     name: "PackageManagerTestAppDeclaresStaticLibrary",
     manifest: "AndroidManifestDeclaresStaticLibrary.xml",
diff --git a/services/tests/PackageManagerServiceTests/unit/Android.bp b/services/tests/PackageManagerServiceTests/unit/Android.bp
index 4aa8abc..334e53a 100644
--- a/services/tests/PackageManagerServiceTests/unit/Android.bp
+++ b/services/tests/PackageManagerServiceTests/unit/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+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_test {
     name: "PackageManagerServiceUnitTests",
     srcs: ["src/**/*.kt"],
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
index e99b071..0fa9a1d 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
@@ -52,8 +52,10 @@
         val collector = mockCollector()
         assertThat(collector.collectAllWebDomains(pkg))
                 .containsExactly("example1.com", "example2.com", "example3.com")
-        assertThat(collector.collectAutoVerifyDomains(pkg))
+        assertThat(collector.collectValidAutoVerifyDomains(pkg))
                 .containsExactly("example1.com", "example2.com", "example3.com", "example4.com")
+        assertThat(collector.collectInvalidAutoVerifyDomains(pkg))
+                .containsExactly("invalid1", "invalid2", "invalid3", "invalid4")
     }
 
     @Test
@@ -62,7 +64,8 @@
         val collector = mockCollector()
         assertThat(collector.collectAllWebDomains(pkg))
                 .containsExactly("example1.com", "example2.com", "example3.com")
-        assertThat(collector.collectAutoVerifyDomains(pkg)).isEmpty()
+        assertThat(collector.collectValidAutoVerifyDomains(pkg)).isEmpty()
+        assertThat(collector.collectInvalidAutoVerifyDomains(pkg)).isEmpty()
     }
 
     @Test
@@ -71,8 +74,10 @@
         val collector = mockCollector(linkedApps = setOf(TEST_PKG_NAME))
         assertThat(collector.collectAllWebDomains(pkg))
                 .containsExactly("example1.com", "example2.com", "example3.com")
-        assertThat(collector.collectAutoVerifyDomains(pkg))
+        assertThat(collector.collectValidAutoVerifyDomains(pkg))
                 .containsExactly("example1.com", "example2.com", "example3.com", "example4.com")
+        assertThat(collector.collectInvalidAutoVerifyDomains(pkg))
+                .containsExactly("invalid1", "invalid2", "invalid3", "invalid4")
     }
 
     @Test
@@ -92,6 +97,7 @@
                                     addDataScheme("https")
                                     addDataPath("/sub", PatternMatcher.PATTERN_LITERAL)
                                     addDataAuthority("example1.com", null)
+                                    addDataAuthority("invalid1", null)
                                 }
                         )
                     },
@@ -111,6 +117,7 @@
                                     addDataScheme("nonWebScheme")
                                     addDataPath("/sub", PatternMatcher.PATTERN_LITERAL)
                                     addDataAuthority("example2.com", null)
+                                    addDataAuthority("invalid2", null)
                                 }
                         )
                     },
@@ -122,7 +129,8 @@
         val collector = mockCollector()
         assertThat(collector.collectAllWebDomains(pkg))
                 .containsExactly("example1.com", "example2.com")
-        assertThat(collector.collectAutoVerifyDomains(pkg)).isEmpty()
+        assertThat(collector.collectValidAutoVerifyDomains(pkg)).isEmpty()
+        assertThat(collector.collectInvalidAutoVerifyDomains(pkg)).isEmpty()
     }
 
     @Test
@@ -132,8 +140,10 @@
 
         assertThat(collector.collectAllWebDomains(pkg))
                 .containsExactly("example1.com", "example2.com", "example3.com")
-        assertThat(collector.collectAutoVerifyDomains(pkg))
+        assertThat(collector.collectValidAutoVerifyDomains(pkg))
                 .containsExactly("example1.com", "example3.com")
+        assertThat(collector.collectInvalidAutoVerifyDomains(pkg))
+                .containsExactly("invalid1", "invalid3")
     }
 
     @Test
@@ -143,7 +153,8 @@
 
         assertThat(collector.collectAllWebDomains(pkg))
                 .containsExactly("example1.com", "example2.com", "example3.com")
-        assertThat(collector.collectAutoVerifyDomains(pkg)).isEmpty()
+        assertThat(collector.collectValidAutoVerifyDomains(pkg)).isEmpty()
+        assertThat(collector.collectInvalidAutoVerifyDomains(pkg)).isEmpty()
     }
 
     @Test
@@ -153,7 +164,8 @@
 
         assertThat(collector.collectAllWebDomains(pkg))
                 .containsExactly("example1.com", "example2.com", "example3.com")
-        assertThat(collector.collectAutoVerifyDomains(pkg)).isEmpty()
+        assertThat(collector.collectValidAutoVerifyDomains(pkg)).isEmpty()
+        assertThat(collector.collectInvalidAutoVerifyDomains(pkg)).isEmpty()
     }
 
     private fun mockCollector(linkedApps: Set<String> = emptySet()): DomainVerificationCollector {
@@ -178,6 +190,7 @@
                     <data android:scheme="https"/>
                     <data android:path="/sub"/>
                     <data android:host="example1.com"/>
+                    <data android:host="invalid1"/>
                 </intent-filter>
                 <intent-filter>
                     <action android:name="android.intent.action.VIEW"/>
@@ -186,6 +199,7 @@
                     <data android:scheme="http"/>
                     <data android:path="/sub2"/>
                     <data android:host="example2.com"/>
+                    <data android:host="invalid2."/>
                 </intent-filter>
                 <intent-filter android:autoVerify="$autoVerify">
                     <action android:name="android.intent.action.VIEW"/>
@@ -194,6 +208,7 @@
                     <data android:scheme="https"/>
                     <data android:path="/sub3"/>
                     <data android:host="example3.com"/>
+                    <data android:host=".invalid3"/>
                 </intent-filter>
                 <intent-filter android:autoVerify="$autoVerify">
                     <action android:name="android.intent.action.VIEW"/>
@@ -201,6 +216,7 @@
                     <data android:scheme="https"/>
                     <data android:path="/sub4"/>
                     <data android:host="example4.com"/>
+                    <data android:host="invalid4"/>
                 </intent-filter>
                 <intent-filter android:autoVerify="$autoVerify">
                     <action android:name="android.intent.action.VIEW"/>
@@ -208,6 +224,7 @@
                     <data android:scheme="https"/>
                     <data android:path="/sub5"/>
                     <data android:host="example5.com"/>
+                    <data android:host="invalid5"/>
                 </intent-filter>
                 <intent-filter android:autoVerify="$autoVerify">
                     <category android:name="android.intent.category.BROWSABLE"/>
@@ -215,11 +232,12 @@
                     <data android:scheme="https"/>
                     <data android:path="/sub5"/>
                     <data android:host="example5.com"/>
+                    <data android:host="invalid5"/>
                 </intent-filter>
             </xml>
         """.trimIndent()
 
-        return mockThrowOnUnmocked<AndroidPackage> {
+        return mockThrowOnUnmocked {
             whenever(packageName) { TEST_PKG_NAME }
             whenever(targetSdkVersion) {
                 if (useV2) Build.VERSION_CODES.S else Build.VERSION_CODES.R
@@ -238,6 +256,7 @@
                                     addDataScheme("https")
                                     addDataPath("/sub", PatternMatcher.PATTERN_LITERAL)
                                     addDataAuthority("example1.com", null)
+                                    addDataAuthority("invalid1", null)
                                 }
                         )
                         addIntent(
@@ -248,6 +267,7 @@
                                     addDataScheme("http")
                                     addDataPath("/sub2", PatternMatcher.PATTERN_LITERAL)
                                     addDataAuthority("example2.com", null)
+                                    addDataAuthority("invalid2", null)
                                 }
                         )
                     },
@@ -261,6 +281,7 @@
                                     addDataScheme("https")
                                     addDataPath("/sub3", PatternMatcher.PATTERN_LITERAL)
                                     addDataAuthority("example3.com", null)
+                                    addDataAuthority("invalid3", null)
                                 }
                         )
                     },
@@ -273,6 +294,7 @@
                                     addDataScheme("https")
                                     addDataPath("/sub4", PatternMatcher.PATTERN_LITERAL)
                                     addDataAuthority("example4.com", null)
+                                    addDataAuthority("invalid4", null)
                                 }
                         )
                         addIntent(
@@ -283,6 +305,7 @@
                                     addDataScheme("https")
                                     addDataPath("/sub5", PatternMatcher.PATTERN_LITERAL)
                                     addDataAuthority("example5.com", null)
+                                    addDataAuthority("invalid5", null)
                                 }
                         )
                         addIntent(
@@ -293,6 +316,7 @@
                                     addDataScheme("https")
                                     addDataPath("/sub6", PatternMatcher.PATTERN_LITERAL)
                                     addDataAuthority("example6.com", null)
+                                    addDataAuthority("invalid6", null)
                                 }
                         )
                     },
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCoreApiTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCoreApiTest.kt
index deb3147..9447f39 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCoreApiTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCoreApiTest.kt
@@ -16,8 +16,9 @@
 
 package com.android.server.pm.test.verify.domain
 
-import android.content.pm.verify.domain.DomainVerificationRequest
+import android.content.pm.verify.domain.DomainSet
 import android.content.pm.verify.domain.DomainVerificationInfo
+import android.content.pm.verify.domain.DomainVerificationRequest
 import android.content.pm.verify.domain.DomainVerificationUserSelection
 import android.os.Parcel
 import android.os.Parcelable
@@ -27,6 +28,7 @@
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
 import java.util.UUID
+import kotlin.random.Random
 
 @RunWith(Parameterized::class)
 class DomainVerificationCoreApiTest {
@@ -40,18 +42,25 @@
             assertThat(value).containsExactlyEntriesIn(other)
         }
 
+        private val massiveSet by lazy {
+            val fragmentOf21 = ".com.example.test.app"
+            val list = mutableListOf("prefix$fragmentOf21")
+            var totalSize = 0
+            // Slightly overshoot a size of 1MB
+            while (totalSize < (1024 * 512)) {
+                val nextValue = "${list.last()}$fragmentOf21"
+                totalSize += nextValue.length
+                list += nextValue
+            }
+            list.toSet()
+        }
+
         @JvmStatic
-        @Parameterized.Parameters
+        @Parameterized.Parameters(name = "{0}")
         fun parameters() = arrayOf(
             Parameter(
-                initial = {
-                    DomainVerificationRequest(
-                        setOf(
-                            "com.test.pkg.one",
-                            "com.test.pkg.two"
-                        )
-                    )
-                },
+                testName = "DomainVerificationRequest",
+                initial = { DomainVerificationRequest(massiveSet) },
                 unparcel = { DomainVerificationRequest.CREATOR.createFromParcel(it) },
                 assertion = { first, second ->
                     assertAll<DomainVerificationRequest, Set<String>>(first, second,
@@ -61,15 +70,12 @@
                 }
             ),
             Parameter(
+                testName = "DomainVerificationInfo",
                 initial = {
                     DomainVerificationInfo(
                         UUID.fromString("703f6d34-6241-4cfd-8176-2e1d23355811"),
                         "com.test.pkg",
-                        mapOf(
-                            "example.com" to 0,
-                            "example.org" to 1,
-                            "example.new" to 1000
-                        )
+                        massiveSet.withIndex().associate { it.value to it.index }
                     )
                 },
                 unparcel = { DomainVerificationInfo.CREATOR.createFromParcel(it) },
@@ -86,17 +92,15 @@
                 }
             ),
             Parameter(
+                testName = "DomainVerificationUserSelection",
                 initial = {
                     DomainVerificationUserSelection(
                         UUID.fromString("703f6d34-6241-4cfd-8176-2e1d23355811"),
                         "com.test.pkg",
                         UserHandle.of(10),
                         true,
-                        mapOf(
-                            "example.com" to true,
-                            "example.org" to false,
-                            "example.new" to true
-                        )
+                        massiveSet.withIndex()
+                            .associate { it.value to (it.index % 3) }
                     )
                 },
                 unparcel = { DomainVerificationUserSelection.CREATOR.createFromParcel(it) },
@@ -114,21 +118,35 @@
                         first, second, { it.isLinkHandlingAllowed },
                         { it.component4() }, IS_EQUAL_TO
                     )
-                    assertAll<DomainVerificationUserSelection, Map<String, Boolean>>(
-                        first, second, { it.hostToUserSelectionMap },
+                    assertAll<DomainVerificationUserSelection, Map<String, Int>>(
+                        first, second, { it.hostToStateMap },
                         { it.component5() }, IS_MAP_EQUAL_TO
                     )
                 }
+            ),
+            Parameter(
+                testName = "DomainSet",
+                initial = { DomainSet(massiveSet) },
+                unparcel = { DomainSet.CREATOR.createFromParcel(it) },
+                assertion = { first, second ->
+                    assertAll<DomainSet, Set<String>>(
+                        first, second,
+                        { it.domains }, assertion = IS_EQUAL_TO
+                    )
+                }
             )
         )
 
         class Parameter<T : Parcelable>(
+            val testName: String,
             val initial: () -> T,
             val unparcel: (Parcel) -> T,
             private val assertion: (first: T, second: T) -> Unit
         ) {
             @Suppress("UNCHECKED_CAST")
             fun assert(first: Any, second: Any) = assertion(first as T, second as T)
+
+            override fun toString() = testName
         }
 
         private fun <T> assertAll(vararg values: T, block: (value: T, other: T) -> Unit) {
@@ -141,11 +159,17 @@
             first: T,
             second: T,
             fieldValue: (T) -> V,
-            componentValue: (T) -> V,
+            componentValue: ((T) -> V)? = null,
             assertion: (value: V, other: V) -> Unit
         ) {
-            val values = arrayOf<Any>(fieldValue(first), fieldValue(second),
-                    componentValue(first), componentValue(second))
+            val values = mutableListOf<Any>(fieldValue(first), fieldValue(second))
+                .apply {
+                    componentValue?.let {
+                        add(it(first))
+                        add(it(second))
+                    }
+                }
+                .toTypedArray()
             values.indices.drop(1).forEach {
                 @Suppress("UNCHECKED_CAST")
                 assertion(values[0] as V, values[it] as V)
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
index 2d23fb4..89394837 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
@@ -244,6 +244,14 @@
                 service(Type.LEGACY_QUERENT, "getLegacyUserState") {
                     getLegacyState(it.targetPackageName, it.userId)
                 },
+                service(Type.OWNER_QUERENT, "getOwnersForDomain") {
+                    // Re-use package name, since the result itself isn't relevant
+                    getOwnersForDomain(it.targetPackageName)
+                },
+                service(Type.OWNER_QUERENT_USER, "getOwnersForDomainUserId") {
+                    // Re-use package name, since the result itself isn't relevant
+                    getOwnersForDomain(it.targetPackageName, it.userId)
+                },
             )
         }
 
@@ -327,6 +335,7 @@
                 domainSetId
             )
         ) {
+            whenever(getName()) { packageName }
             whenever(getPkg()) { mockPkg(packageName) }
             whenever(this.domainSetId) { domainSetId }
             whenever(userState) {
@@ -357,6 +366,8 @@
             Type.SELECTOR_USER -> approvedUserSelector(verifyCrossUser = true)
             Type.LEGACY_QUERENT -> legacyQuerent()
             Type.LEGACY_SELECTOR -> legacyUserSelector()
+            Type.OWNER_QUERENT -> ownerQuerent(verifyCrossUser = false)
+            Type.OWNER_QUERENT_USER -> ownerQuerent(verifyCrossUser = true)
         }.run { /*exhaust*/ }
     }
 
@@ -628,6 +639,80 @@
         runTestCases(callingUserId, notCallingUserId, throws = false)
     }
 
+    private fun ownerQuerent(verifyCrossUser: Boolean) {
+        val allowQueryAll = AtomicBoolean(false)
+        val allowUserSelection = AtomicBoolean(false)
+        val allowInteractAcrossUsers = AtomicBoolean(false)
+        val context: Context = mockThrowOnUnmocked {
+            initPermission(
+                allowQueryAll,
+                android.Manifest.permission.QUERY_ALL_PACKAGES
+            )
+            initPermission(
+                allowUserSelection,
+                android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION
+            )
+            initPermission(
+                allowInteractAcrossUsers,
+                android.Manifest.permission.INTERACT_ACROSS_USERS
+            )
+        }
+        val target = params.construct(context)
+
+        fun runTestCases(callingUserId: Int, targetUserId: Int, throws: Boolean) {
+            // Owner querent makes no distinction by UID
+            val allUids = INTERNAL_UIDS + VERIFIER_UID + NON_VERIFIER_UID
+            if (throws) {
+                allUids.forEach {
+                    assertFails {
+                        runMethod(target, it, visible = true, callingUserId, targetUserId)
+                    }
+                }
+            } else {
+                allUids.forEach {
+                    runMethod(target, it, visible = true, callingUserId, targetUserId)
+                }
+            }
+        }
+
+        val callingUserId = 0
+        val notCallingUserId = 1
+
+        runTestCases(callingUserId, callingUserId, throws = true)
+        if (verifyCrossUser) {
+            runTestCases(callingUserId, notCallingUserId, throws = true)
+        }
+
+        allowQueryAll.set(true)
+
+        runTestCases(callingUserId, callingUserId, throws = true)
+        if (verifyCrossUser) {
+            runTestCases(callingUserId, notCallingUserId, throws = true)
+        }
+
+        allowUserSelection.set(true)
+
+        runTestCases(callingUserId, callingUserId, throws = false)
+        if (verifyCrossUser) {
+            runTestCases(callingUserId, notCallingUserId, throws = true)
+        }
+
+        allowQueryAll.set(false)
+
+        runTestCases(callingUserId, callingUserId, throws = true)
+        if (verifyCrossUser) {
+            runTestCases(callingUserId, notCallingUserId, throws = true)
+        }
+
+        allowQueryAll.set(true)
+        allowInteractAcrossUsers.set(true)
+
+        runTestCases(callingUserId, callingUserId, throws = false)
+        if (verifyCrossUser) {
+            runTestCases(callingUserId, notCallingUserId, throws = false)
+        }
+    }
+
     private fun Context.initPermission(boolean: AtomicBoolean, permission: String) {
         whenever(enforcePermission(eq(permission), anyInt(), anyInt(), anyString())) {
             if (!boolean.get()) {
@@ -694,6 +779,12 @@
         LEGACY_QUERENT,
 
         // Holding the legacy preferred apps permission
-        LEGACY_SELECTOR
+        LEGACY_SELECTOR,
+
+        // Holding user setting permission, but not targeting a package
+        OWNER_QUERENT,
+
+        // Holding user setting permission, but not targeting a package, but targeting cross user
+        OWNER_QUERENT_USER,
     }
 }
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerUserSelectionOverrideTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerUserSelectionOverrideTest.kt
new file mode 100644
index 0000000..48056a2
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerUserSelectionOverrideTest.kt
@@ -0,0 +1,174 @@
+/*
+ * 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.pm.test.verify.domain
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.content.pm.parsing.component.ParsedActivity
+import android.content.pm.parsing.component.ParsedIntentInfo
+import android.content.pm.verify.domain.DomainVerificationManager
+import android.content.pm.verify.domain.DomainVerificationUserSelection
+import android.os.Build
+import android.os.PatternMatcher
+import android.os.Process
+import android.util.ArraySet
+import androidx.test.InstrumentationRegistry
+import com.android.server.pm.PackageSetting
+import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.verify.domain.DomainVerificationService
+import com.android.server.testutils.mockThrowOnUnmocked
+import com.android.server.testutils.whenever
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyLong
+import org.mockito.ArgumentMatchers.anyString
+import java.util.UUID
+
+class DomainVerificationManagerUserSelectionOverrideTest {
+
+    companion object {
+        private const val PKG_ONE = "com.test.one"
+        private const val PKG_TWO = "com.test.two"
+        private val UUID_ONE = UUID.fromString("1b041c96-8d37-4932-a858-561bfac5947c")
+        private val UUID_TWO = UUID.fromString("a3389c16-7f9f-4e86-85e3-500d1249c74c")
+
+        private val DOMAIN_ONE =
+            DomainVerificationManagerUserSelectionOverrideTest::class.java.packageName
+
+        private const val STATE_NONE = DomainVerificationUserSelection.DOMAIN_STATE_NONE
+        private const val STATE_SELECTED = DomainVerificationUserSelection.DOMAIN_STATE_SELECTED
+        private const val STATE_VERIFIED = DomainVerificationUserSelection.DOMAIN_STATE_VERIFIED
+    }
+
+    private val pkg1 = mockPkgSetting(PKG_ONE, UUID_ONE)
+    private val pkg2 = mockPkgSetting(PKG_TWO, UUID_TWO)
+
+    fun makeManager(): DomainVerificationManager =
+        DomainVerificationService(mockThrowOnUnmocked {
+            // Assume the test has every permission necessary
+            whenever(enforcePermission(anyString(), anyInt(), anyInt(), anyString()))
+            whenever(checkPermission(anyString(), anyInt(), anyInt())) {
+                PackageManager.PERMISSION_GRANTED
+            }
+        }, mockThrowOnUnmocked {
+            whenever(linkedApps) { ArraySet<String>() }
+        }, mockThrowOnUnmocked {
+            whenever(isChangeEnabled(anyLong(), any())) { true }
+        }).apply {
+            setConnection(mockThrowOnUnmocked {
+                whenever(filterAppAccess(anyString(), anyInt(), anyInt())) { false }
+                whenever(scheduleWriteSettings())
+
+                // Need to provide an internal UID so some permission checks are ignored
+                whenever(callingUid) { Process.ROOT_UID }
+                whenever(callingUserId) { 0 }
+                whenever(getPackageSettingLocked(PKG_ONE)) { pkg1 }
+                whenever(getPackageSettingLocked(PKG_TWO)) { pkg2 }
+                whenever(getPackageLocked(PKG_ONE)) { pkg1.getPkg() }
+                whenever(getPackageLocked(PKG_TWO)) { pkg2.getPkg() }
+            })
+            addPackage(pkg1)
+            addPackage(pkg2)
+
+            // Starting state for all tests is to have domain 1 enabled for the first package
+            setDomainVerificationUserSelection(UUID_ONE, setOf(DOMAIN_ONE), true)
+
+            assertThat(stateFor(PKG_ONE, DOMAIN_ONE)).isEqualTo(STATE_SELECTED)
+        }
+
+    fun mockPkgSetting(pkgName: String, domainSetId: UUID) = mockThrowOnUnmocked<PackageSetting> {
+        val pkg = mockThrowOnUnmocked<AndroidPackage> {
+            whenever(packageName) { pkgName }
+            whenever(targetSdkVersion) { Build.VERSION_CODES.S }
+
+            val activityList = listOf(
+                ParsedActivity().apply {
+                    addIntent(
+                        ParsedIntentInfo().apply {
+                            autoVerify = true
+                            addAction(Intent.ACTION_VIEW)
+                            addCategory(Intent.CATEGORY_BROWSABLE)
+                            addCategory(Intent.CATEGORY_DEFAULT)
+                            addDataScheme("http")
+                            addDataScheme("https")
+                            addDataPath("/sub", PatternMatcher.PATTERN_LITERAL)
+                            addDataAuthority(DOMAIN_ONE, null)
+                        }
+                    )
+                    addIntent(
+                        ParsedIntentInfo().apply {
+                            autoVerify = true
+                            addAction(Intent.ACTION_VIEW)
+                            addCategory(Intent.CATEGORY_BROWSABLE)
+                            addCategory(Intent.CATEGORY_DEFAULT)
+                            addDataScheme("http")
+                            addDataPath("/sub2", PatternMatcher.PATTERN_LITERAL)
+                            addDataAuthority("example2.com", null)
+                        }
+                    )
+                },
+            )
+
+            whenever(activities) { activityList }
+        }
+
+        whenever(getPkg()) { pkg }
+        whenever(getName()) { pkgName }
+        whenever(this.domainSetId) { domainSetId }
+        whenever(getInstantApp(anyInt())) { false }
+        whenever(firstInstallTime) { 0L }
+    }
+
+    @Test
+    fun anotherPackageTakeoverSuccess() {
+        val manager = makeManager()
+
+        // Attempt override by package 2
+        manager.setDomainVerificationUserSelection(UUID_TWO, setOf(DOMAIN_ONE), true)
+
+        // 1 loses approval
+        assertThat(manager.stateFor(PKG_ONE, DOMAIN_ONE)).isEqualTo(STATE_NONE)
+
+        // 2 gains approval
+        assertThat(manager.stateFor(PKG_TWO, DOMAIN_ONE)).isEqualTo(STATE_SELECTED)
+
+        // 2 is the only owner
+        assertThat(manager.getOwnersForDomain(DOMAIN_ONE).map { it.packageName })
+            .containsExactly(PKG_TWO)
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun anotherPackageTakeoverFailure() {
+        val manager = makeManager()
+
+        // Verify 1 to give it a higher approval level
+        manager.setDomainVerificationStatus(UUID_ONE, setOf(DOMAIN_ONE),
+            DomainVerificationManager.STATE_SUCCESS)
+        assertThat(manager.stateFor(PKG_ONE, DOMAIN_ONE)).isEqualTo(STATE_VERIFIED)
+        assertThat(manager.getOwnersForDomain(DOMAIN_ONE).map { it.packageName })
+            .containsExactly(PKG_ONE)
+
+        // Attempt override by package 2
+        manager.setDomainVerificationUserSelection(UUID_TWO, setOf(DOMAIN_ONE), true)
+    }
+
+    private fun DomainVerificationManager.stateFor(pkgName: String, host: String) =
+        getDomainVerificationUserSelection(pkgName)!!.hostToStateMap[host]
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationModelExtensions.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationModelExtensions.kt
index a76d8ce..439048c 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationModelExtensions.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationModelExtensions.kt
@@ -34,7 +34,7 @@
 operator fun DomainVerificationUserSelection.component2() = packageName
 operator fun DomainVerificationUserSelection.component3() = user
 operator fun DomainVerificationUserSelection.component4() = isLinkHandlingAllowed
-operator fun DomainVerificationUserSelection.component5() = hostToUserSelectionMap
+operator fun DomainVerificationUserSelection.component5() = hostToStateMap
 
 operator fun DomainVerificationPersistence.ReadResult.component1() = active
 operator fun DomainVerificationPersistence.ReadResult.component2() = restored
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationProxyTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationProxyTest.kt
index db541f6..91e5bec 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationProxyTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationProxyTest.kt
@@ -122,7 +122,7 @@
             whenever(setDomainVerificationStatusInternal(anyInt(), any(), any(), anyInt()))
         }
         collector = mockThrowOnUnmocked {
-            whenever(collectAutoVerifyDomains(any())) {
+            whenever(collectValidAutoVerifyDomains(any())) {
                 when (val pkgName = (arguments[0] as AndroidPackage).packageName) {
                     TEST_PKG_NAME_TARGET_ONE -> ArraySet(setOf("example1.com", "example2.com"))
                     TEST_PKG_NAME_TARGET_TWO -> ArraySet(setOf("example3.com", "example4.com"))
@@ -477,7 +477,7 @@
                     whenever(
                         addPowerSaveTempWhitelistApp(
                             anyInt(), anyString(), anyLong(), anyInt(),
-                            anyBoolean(), anyString()
+                            anyBoolean(), anyInt(), anyString()
                         )
                     )
                 }
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
index 48518f46..010eacf 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
@@ -237,6 +237,7 @@
                 TEST_UUID
             )
         ) {
+            whenever(getName()) { TEST_PKG }
             whenever(getPkg()) { mockPkg() }
             whenever(domainSetId) { TEST_UUID }
             whenever(userState) {
diff --git a/services/tests/inprocesstests/Android.bp b/services/tests/inprocesstests/Android.bp
index 6dd059f..7c237ac 100644
--- a/services/tests/inprocesstests/Android.bp
+++ b/services/tests/inprocesstests/Android.bp
@@ -1,3 +1,12 @@
+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_test {
     name: "FrameworksInProcessTests",
     srcs: ["src/**/*.java"],
diff --git a/services/tests/mockingservicestests/jni/Android.bp b/services/tests/mockingservicestests/jni/Android.bp
index 928065a..a32bf2c 100644
--- a/services/tests/mockingservicestests/jni/Android.bp
+++ b/services/tests/mockingservicestests/jni/Android.bp
@@ -1,3 +1,12 @@
+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"],
+}
+
 cc_library_shared {
     name: "libactivitymanagermockingservicestestjni",
 
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 9109881..51c9b0d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -85,6 +85,7 @@
 import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
 import android.app.AppOpsManager;
+import android.app.BroadcastOptions;
 import android.app.IActivityManager;
 import android.app.IAlarmCompleteListener;
 import android.app.IAlarmListener;
@@ -1649,8 +1650,8 @@
                 eq(FLAG_ALLOW_WHILE_IDLE_COMPAT | FLAG_STANDALONE), isNull(), isNull(),
                 eq(Process.myUid()), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
 
-        final Bundle idleOptions = bundleCaptor.getValue();
-        final int type = idleOptions.getInt("android:broadcast.temporaryAppWhitelistType");
+        final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
+        final int type = idleOptions.getTemporaryAppAllowlistType();
         assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, type);
     }
 
@@ -1669,8 +1670,8 @@
                 eq(alarmPi), isNull(), isNull(), eq(FLAG_ALLOW_WHILE_IDLE_COMPAT), isNull(),
                 isNull(), eq(Process.myUid()), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
 
-        final Bundle idleOptions = bundleCaptor.getValue();
-        final int type = idleOptions.getInt("android:broadcast.temporaryAppWhitelistType");
+        final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
+        final int type = idleOptions.getTemporaryAppAllowlistType();
         assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, type);
     }
 
@@ -1716,8 +1717,8 @@
                 isNull(), eq(alarmClock), eq(Process.myUid()), eq(TEST_CALLING_PACKAGE),
                 bundleCaptor.capture());
 
-        final Bundle idleOptions = bundleCaptor.getValue();
-        final int type = idleOptions.getInt("android:broadcast.temporaryAppWhitelistType");
+        final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
+        final int type = idleOptions.getTemporaryAppAllowlistType();
         assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, type);
     }
 
@@ -1742,8 +1743,8 @@
                 eq(FLAG_ALLOW_WHILE_IDLE | FLAG_STANDALONE), isNull(), isNull(),
                 eq(Process.myUid()), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
 
-        final Bundle idleOptions = bundleCaptor.getValue();
-        final int type = idleOptions.getInt("android:broadcast.temporaryAppWhitelistType");
+        final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
+        final int type = idleOptions.getTemporaryAppAllowlistType();
         assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, type);
     }
 
@@ -1772,8 +1773,8 @@
                 eq(FLAG_ALLOW_WHILE_IDLE_COMPAT | FLAG_STANDALONE), isNull(), isNull(),
                 eq(Process.myUid()), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
 
-        final Bundle idleOptions = bundleCaptor.getValue();
-        final int type = idleOptions.getInt("android:broadcast.temporaryAppWhitelistType");
+        final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
+        final int type = idleOptions.getTemporaryAppAllowlistType();
         assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, type);
     }
 
@@ -1797,8 +1798,8 @@
                 eq(alarmPi), isNull(), isNull(), eq(FLAG_ALLOW_WHILE_IDLE_COMPAT), isNull(),
                 isNull(), eq(Process.myUid()), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
 
-        final Bundle idleOptions = bundleCaptor.getValue();
-        final int type = idleOptions.getInt("android:broadcast.temporaryAppWhitelistType");
+        final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
+        final int type = idleOptions.getTemporaryAppAllowlistType();
         assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, type);
     }
 
@@ -1822,8 +1823,8 @@
                 eq(alarmPi), isNull(), isNull(), eq(FLAG_ALLOW_WHILE_IDLE_COMPAT), isNull(),
                 isNull(), eq(Process.myUid()), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
 
-        final Bundle idleOptions = bundleCaptor.getValue();
-        final int type = idleOptions.getInt("android:broadcast.temporaryAppWhitelistType");
+        final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
+        final int type = idleOptions.getTemporaryAppAllowlistType();
         assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED, type);
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index a382e85..1c45203 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -46,6 +46,7 @@
 import static com.android.server.am.ProcessList.HOME_APP_ADJ;
 import static com.android.server.am.ProcessList.PERCEPTIBLE_APP_ADJ;
 import static com.android.server.am.ProcessList.PERCEPTIBLE_LOW_APP_ADJ;
+import static com.android.server.am.ProcessList.PERCEPTIBLE_MEDIUM_APP_ADJ;
 import static com.android.server.am.ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ;
 import static com.android.server.am.ProcessList.PERSISTENT_PROC_ADJ;
 import static com.android.server.am.ProcessList.PERSISTENT_SERVICE_ADJ;
@@ -877,6 +878,39 @@
 
     @SuppressWarnings("GuardedBy")
     @Test
+    public void testUpdateOomAdj_DoOne_Service_MediumPerceptible() {
+        {
+            ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                    MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+            ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                    MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+            bindService(app, client, null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
+            client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
+            sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+            sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+            assertEquals(PERCEPTIBLE_MEDIUM_APP_ADJ, app.mState.getSetAdj());
+        }
+
+        {
+            ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                    MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+            ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                    MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+            WindowProcessController wpc = client.getWindowProcessController();
+            doReturn(true).when(wpc).isHeavyWeightProcess();
+            bindService(app, client, null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
+            client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
+            sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+            sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+            doReturn(false).when(wpc).isHeavyWeightProcess();
+
+            assertEquals(PERCEPTIBLE_MEDIUM_APP_ADJ, app.mState.getSetAdj());
+        }
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
     public void testUpdateOomAdj_DoOne_Service_Other() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 728b97c..f1d8e6c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -27,11 +27,14 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -44,6 +47,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.dx.mockito.inline.extended.StaticMockitoSession;
+import com.android.internal.R;
 import com.android.server.LocalServices;
 import com.android.server.display.LocalDisplayAdapter.BacklightAdapter;
 import com.android.server.lights.LightsManager;
@@ -98,6 +102,9 @@
 
     @Mock
     private LocalDisplayAdapter.SurfaceControlProxy mSurfaceControlProxy;
+    private static final float[] DISPLAY_RANGE_NITS = { 2.685f, 478.5f };
+    private static final int[] BACKLIGHT_RANGE = { 1, 255 };
+    private static final float[] BACKLIGHT_RANGE_ZERO_TO_ONE = { 0.0f, 1.0f };
 
     @Before
     public void setUp() throws Exception {
@@ -114,6 +121,18 @@
                 mListener, mInjector);
         spyOn(mAdapter);
         doReturn(mMockedContext).when(mAdapter).getOverlayContext();
+
+        TypedArray mockNitsRange = createFloatTypedArray(DISPLAY_RANGE_NITS);
+        when(mMockedResources.obtainTypedArray(R.array.config_screenBrightnessNits))
+                .thenReturn(mockNitsRange);
+        when(mMockedResources.getIntArray(R.array.config_screenBrightnessBacklight))
+                .thenReturn(BACKLIGHT_RANGE);
+        when(mMockedResources.getFloat(com.android.internal.R.dimen
+                .config_screenBrightnessSettingMinimumFloat))
+                .thenReturn(BACKLIGHT_RANGE_ZERO_TO_ONE[0]);
+        when(mMockedResources.getFloat(com.android.internal.R.dimen
+                .config_screenBrightnessSettingMaximumFloat))
+                .thenReturn(BACKLIGHT_RANGE_ZERO_TO_ONE[1]);
     }
 
     @After
@@ -573,6 +592,7 @@
                         new DisplayModeDirector.RefreshRateRange(60f, 60f),
                         new DisplayModeDirector.RefreshRateRange(60f, 60f)
                 ));
+        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
         verify(mSurfaceControlProxy).setDesiredDisplayModeSpecs(display.token,
                 new SurfaceControl.DesiredDisplayModeSpecs(
                         /* baseModeId */ 0,
@@ -629,13 +649,13 @@
         // Test as default display
         BacklightAdapter ba = new BacklightAdapter(displayToken, true /*isDefault*/,
                 mSurfaceControlProxy);
-        ba.setBrightness(0.514f);
+        ba.setBacklight(0.514f);
         verify(mSurfaceControlProxy).setDisplayBrightness(displayToken, 0.514f);
 
         // Test as not default display
         BacklightAdapter ba2 = new BacklightAdapter(displayToken, false /*isDefault*/,
                 mSurfaceControlProxy);
-        ba2.setBrightness(0.323f);
+        ba2.setBacklight(0.323f);
         verify(mSurfaceControlProxy).setDisplayBrightness(displayToken, 0.323f);
     }
 
@@ -648,7 +668,7 @@
 
         BacklightAdapter ba = new BacklightAdapter(displayToken, true /*isDefault*/,
                 mSurfaceControlProxy);
-        ba.setBrightness(0.123f);
+        ba.setBacklight(0.123f);
         verify(mMockedBacklight).setBrightness(0.123f);
     }
 
@@ -661,7 +681,7 @@
 
         BacklightAdapter ba = new BacklightAdapter(displayToken, false /*isDefault*/,
                 mSurfaceControlProxy);
-        ba.setBrightness(0.456f);
+        ba.setBacklight(0.456f);
 
         // Adapter does not forward any brightness in this case.
         verify(mMockedBacklight, never()).setBrightness(anyFloat());
@@ -864,4 +884,23 @@
         }
     }
 
+    private TypedArray createFloatTypedArray(float[] vals) {
+        TypedArray mockArray = mock(TypedArray.class);
+        when(mockArray.length()).thenAnswer(invocation -> {
+            return vals.length;
+        });
+        when(mockArray.getFloat(anyInt(), anyFloat())).thenAnswer(invocation -> {
+            final float def = (float) invocation.getArguments()[1];
+            if (vals == null) {
+                return def;
+            }
+            int idx = (int) invocation.getArguments()[0];
+            if (idx >= 0 && idx < vals.length) {
+                return vals[idx];
+            } else {
+                return def;
+            }
+        });
+        return mockArray;
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
index 775276b..f7f5928 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -19,6 +19,7 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 
@@ -611,6 +612,7 @@
 
     private static NetworkCapabilities createCapabilities() {
         return new NetworkCapabilities().addCapability(NET_CAPABILITY_INTERNET)
+                .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
                 .addCapability(NET_CAPABILITY_VALIDATED);
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 88a691b..29db740 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -31,6 +31,7 @@
 import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
 import static com.android.server.job.JobSchedulerService.WORKING_INDEX;
 import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+import static com.android.server.job.JobSchedulerService.sSystemClock;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -58,6 +59,7 @@
 import android.app.IActivityManager;
 import android.app.IUidObserver;
 import android.app.job.JobInfo;
+import android.app.usage.UsageEvents;
 import android.app.usage.UsageStatsManager;
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.BroadcastReceiver;
@@ -85,6 +87,7 @@
 import com.android.server.job.JobStore;
 import com.android.server.job.controllers.QuotaController.ExecutionStats;
 import com.android.server.job.controllers.QuotaController.QcConstants;
+import com.android.server.job.controllers.QuotaController.ShrinkableDebits;
 import com.android.server.job.controllers.QuotaController.TimingSession;
 import com.android.server.usage.AppStandbyInternal;
 
@@ -125,6 +128,7 @@
     private int mSourceUid;
     private PowerAllowlistInternal.TempAllowlistChangeListener mTempAllowlistListener;
     private IUidObserver mUidObserver;
+    private UsageStatsManagerInternal.UsageEventListener mUsageEventListener;
     DeviceConfig.Properties.Builder mDeviceConfigPropertiesBuilder;
 
     private MockitoSession mMockingSession;
@@ -218,6 +222,8 @@
                 ArgumentCaptor.forClass(IUidObserver.class);
         ArgumentCaptor<PowerAllowlistInternal.TempAllowlistChangeListener> taChangeCaptor =
                 ArgumentCaptor.forClass(PowerAllowlistInternal.TempAllowlistChangeListener.class);
+        ArgumentCaptor<UsageStatsManagerInternal.UsageEventListener> ueListenerCaptor =
+                ArgumentCaptor.forClass(UsageStatsManagerInternal.UsageEventListener.class);
         mQuotaController = new QuotaController(mJobSchedulerService,
                 mock(BackgroundJobsController.class), mock(ConnectivityController.class));
 
@@ -229,6 +235,8 @@
         verify(mPowerAllowlistInternal)
                 .registerTempAllowlistChangeListener(taChangeCaptor.capture());
         mTempAllowlistListener = taChangeCaptor.getValue();
+        verify(mUsageStatsManager).registerListener(ueListenerCaptor.capture());
+        mUsageEventListener = ueListenerCaptor.getValue();
         try {
             verify(activityManager).registerUidObserver(
                     uidObserverCaptor.capture(),
@@ -288,7 +296,7 @@
                 verify(foregroundUids, timeout(2 * SECOND_IN_MILLIS).times(1)).delete(eq(uid));
                 assertFalse(foregroundUids.get(uid));
             }
-            waitForQuietBackground();
+            waitForNonDelayedMessagesProcessed();
         } catch (Exception e) {
             fail("exception encountered: " + e.getMessage());
         }
@@ -385,13 +393,8 @@
         }
     }
 
-    private void waitForQuietBackground() throws Exception {
-        for (int i = 0; i < 5; ++i) {
-            if (!mQuotaController.isActiveBackgroundProcessing()) {
-                break;
-            }
-            Thread.sleep(500);
-        }
+    private void waitForNonDelayedMessagesProcessed() {
+        mQuotaController.getHandler().runWithScissors(() -> {}, 15_000);
     }
 
     @Test
@@ -1323,6 +1326,46 @@
     }
 
     @Test
+    public void testGetMaxJobExecutionTimeLocked_Regular_Active() {
+        JobStatus job = createJobStatus("testGetMaxJobExecutionTimeLocked_Regular_Active", 0);
+        setDeviceConfigLong(QcConstants.KEY_ALLOWED_TIME_PER_PERIOD_MS, 10 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_WINDOW_SIZE_ACTIVE_MS, 10 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_MAX_EXECUTION_TIME_MS, 2 * HOUR_IN_MILLIS);
+        setDischarging();
+        setStandbyBucket(ACTIVE_INDEX, job);
+        setProcessState(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
+
+        // ACTIVE apps (where allowed time = window size) should be capped at max execution limit.
+        synchronized (mQuotaController.mLock) {
+            assertEquals(2 * HOUR_IN_MILLIS,
+                    mQuotaController.getMaxJobExecutionTimeMsLocked((job)));
+        }
+
+        // Make sure sessions are factored in properly.
+        mQuotaController.saveTimingSession(0, SOURCE_PACKAGE,
+                createTimingSession(sElapsedRealtimeClock.millis() - (6 * HOUR_IN_MILLIS),
+                        30 * MINUTE_IN_MILLIS, 1), false);
+        synchronized (mQuotaController.mLock) {
+            assertEquals(90 * MINUTE_IN_MILLIS,
+                    mQuotaController.getMaxJobExecutionTimeMsLocked((job)));
+        }
+
+        mQuotaController.saveTimingSession(0, SOURCE_PACKAGE,
+                createTimingSession(sElapsedRealtimeClock.millis() - (5 * HOUR_IN_MILLIS),
+                        30 * MINUTE_IN_MILLIS, 1), false);
+        mQuotaController.saveTimingSession(0, SOURCE_PACKAGE,
+                createTimingSession(sElapsedRealtimeClock.millis() - (4 * HOUR_IN_MILLIS),
+                        30 * MINUTE_IN_MILLIS, 1), false);
+        mQuotaController.saveTimingSession(0, SOURCE_PACKAGE,
+                createTimingSession(sElapsedRealtimeClock.millis() - (3 * HOUR_IN_MILLIS),
+                        25 * MINUTE_IN_MILLIS, 1), false);
+        synchronized (mQuotaController.mLock) {
+            assertEquals(5 * MINUTE_IN_MILLIS,
+                    mQuotaController.getMaxJobExecutionTimeMsLocked((job)));
+        }
+    }
+
+    @Test
     public void testGetMaxJobExecutionTimeLocked_EJ() {
         final long timeUsedMs = 3 * MINUTE_IN_MILLIS;
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
@@ -1330,7 +1373,9 @@
                         timeUsedMs, 5), true);
         JobStatus job = createExpeditedJobStatus("testGetMaxJobExecutionTimeLocked_EJ", 0);
         setStandbyBucket(RARE_INDEX, job);
-        mQuotaController.maybeStartTrackingJobLocked(job, null);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(job, null);
+        }
 
         setCharging();
         synchronized (mQuotaController.mLock) {
@@ -5158,4 +5203,257 @@
                 eq(10 * SECOND_IN_MILLIS));
         verify(handler, never()).sendMessageDelayed(any(), eq(remainingTimeMs));
     }
+
+    @Test
+    public void testEJDebitTallying() {
+        setStandbyBucket(RARE_INDEX);
+        setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
+        setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RARE_MS, 10 * MINUTE_IN_MILLIS);
+        // 15 seconds for each 30 second chunk.
+        setDeviceConfigLong(QcConstants.KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS, 30 * SECOND_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_TOP_APP_MS, 15 * SECOND_IN_MILLIS);
+
+        // No history. Debits should be 0.
+        ShrinkableDebits debit = mQuotaController.getEJDebitsLocked(SOURCE_USER_ID, SOURCE_PACKAGE);
+        assertEquals(0, debit.getTallyLocked());
+        assertEquals(10 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        // Regular job shouldn't affect EJ tally.
+        JobStatus regJob = createJobStatus("testEJDebitTallying", 1);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(regJob, null);
+            mQuotaController.prepareForExecutionLocked(regJob);
+        }
+        advanceElapsedClock(5000);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(regJob, null, false);
+        }
+        assertEquals(0, debit.getTallyLocked());
+        assertEquals(10 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        // EJ job should affect EJ tally.
+        JobStatus eJob = createExpeditedJobStatus("testEJDebitTallying", 2);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(eJob, null);
+            mQuotaController.prepareForExecutionLocked(eJob);
+        }
+        advanceElapsedClock(5 * MINUTE_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(eJob, null, false);
+        }
+        assertEquals(5 * MINUTE_IN_MILLIS, debit.getTallyLocked());
+        assertEquals(5 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        // Instantaneous event for a different user shouldn't affect tally.
+        advanceElapsedClock(5 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_INTERACTION_MS, MINUTE_IN_MILLIS);
+
+        UsageEvents.Event event =
+                new UsageEvents.Event(UsageEvents.Event.USER_INTERACTION, sSystemClock.millis());
+        event.mPackage = SOURCE_PACKAGE;
+        mUsageEventListener.onUsageEvent(SOURCE_USER_ID + 10, event);
+        assertEquals(5 * MINUTE_IN_MILLIS, debit.getTallyLocked());
+
+        // Instantaneous event for correct user should reduce tally.
+        advanceElapsedClock(5 * MINUTE_IN_MILLIS);
+
+        mUsageEventListener.onUsageEvent(SOURCE_USER_ID, event);
+        waitForNonDelayedMessagesProcessed();
+        assertEquals(4 * MINUTE_IN_MILLIS, debit.getTallyLocked());
+        assertEquals(6 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        // Activity start shouldn't reduce tally, but duration with activity started should affect
+        // remaining EJ time.
+        advanceElapsedClock(5 * MINUTE_IN_MILLIS);
+        event = new UsageEvents.Event(UsageEvents.Event.ACTIVITY_RESUMED, sSystemClock.millis());
+        event.mPackage = SOURCE_PACKAGE;
+        mUsageEventListener.onUsageEvent(SOURCE_USER_ID, event);
+        waitForNonDelayedMessagesProcessed();
+        advanceElapsedClock(30 * SECOND_IN_MILLIS);
+        assertEquals(4 * MINUTE_IN_MILLIS, debit.getTallyLocked());
+        assertEquals(6 * MINUTE_IN_MILLIS + 15 * SECOND_IN_MILLIS,
+                mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+        advanceElapsedClock(30 * SECOND_IN_MILLIS);
+        assertEquals(4 * MINUTE_IN_MILLIS, debit.getTallyLocked());
+        assertEquals(6 * MINUTE_IN_MILLIS + 30 * SECOND_IN_MILLIS,
+                mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        // With activity pausing/stopping/destroying, tally should be updated.
+        advanceElapsedClock(MINUTE_IN_MILLIS);
+        event = new UsageEvents.Event(UsageEvents.Event.ACTIVITY_DESTROYED, sSystemClock.millis());
+        event.mPackage = SOURCE_PACKAGE;
+        mUsageEventListener.onUsageEvent(SOURCE_USER_ID, event);
+        waitForNonDelayedMessagesProcessed();
+        assertEquals(3 * MINUTE_IN_MILLIS, debit.getTallyLocked());
+        assertEquals(7 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
+    @Test
+    public void testEJDebitTallying_StaleSession() {
+        setStandbyBucket(RARE_INDEX);
+        setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RARE_MS, 10 * MINUTE_IN_MILLIS);
+
+        final long nowElapsed = sElapsedRealtimeClock.millis();
+        TimingSession ts = new TimingSession(nowElapsed, nowElapsed + 10 * MINUTE_IN_MILLIS, 5);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, ts, true);
+
+        // Make the session stale.
+        advanceElapsedClock(12 * MINUTE_IN_MILLIS + mQcConstants.EJ_WINDOW_SIZE_MS);
+
+        // With lazy deletion, we don't update the tally until getRemainingEJExecutionTimeLocked()
+        // is called, so call that first.
+        assertEquals(10 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+        ShrinkableDebits debit = mQuotaController.getEJDebitsLocked(SOURCE_USER_ID, SOURCE_PACKAGE);
+        assertEquals(0, debit.getTallyLocked());
+    }
+
+    /**
+     * Tests that rewards are properly accounted when there's no EJ running and the rewards exceed
+     * the accumulated debits.
+     */
+    @Test
+    public void testEJDebitTallying_RewardExceedDebits_NoActiveSession() {
+        setStandbyBucket(WORKING_INDEX);
+        setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
+        setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_WORKING_MS, 30 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_INTERACTION_MS, MINUTE_IN_MILLIS);
+
+        final long nowElapsed = sElapsedRealtimeClock.millis();
+        TimingSession ts = new TimingSession(nowElapsed - 5 * MINUTE_IN_MILLIS,
+                nowElapsed - 4 * MINUTE_IN_MILLIS, 2);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, ts, true);
+
+        ShrinkableDebits debit = mQuotaController.getEJDebitsLocked(SOURCE_USER_ID, SOURCE_PACKAGE);
+        assertEquals(MINUTE_IN_MILLIS, debit.getTallyLocked());
+        assertEquals(29 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(30 * SECOND_IN_MILLIS);
+        UsageEvents.Event event =
+                new UsageEvents.Event(UsageEvents.Event.USER_INTERACTION, sSystemClock.millis());
+        event.mPackage = SOURCE_PACKAGE;
+        mUsageEventListener.onUsageEvent(SOURCE_USER_ID, event);
+        waitForNonDelayedMessagesProcessed();
+        assertEquals(0, debit.getTallyLocked());
+        assertEquals(30 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(MINUTE_IN_MILLIS);
+        assertEquals(0, debit.getTallyLocked());
+        assertEquals(30 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        // Excessive rewards don't increase maximum quota.
+        event = new UsageEvents.Event(UsageEvents.Event.USER_INTERACTION, sSystemClock.millis());
+        event.mPackage = SOURCE_PACKAGE;
+        mUsageEventListener.onUsageEvent(SOURCE_USER_ID, event);
+        waitForNonDelayedMessagesProcessed();
+        assertEquals(0, debit.getTallyLocked());
+        assertEquals(30 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
+    /**
+     * Tests that rewards are properly accounted when there's an active EJ running and the rewards
+     * exceed the accumulated debits.
+     */
+    @Test
+    public void testEJDebitTallying_RewardExceedDebits_ActiveSession() {
+        setStandbyBucket(WORKING_INDEX);
+        setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
+        setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_WORKING_MS, 30 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_INTERACTION_MS, MINUTE_IN_MILLIS);
+        // 15 seconds for each 30 second chunk.
+        setDeviceConfigLong(QcConstants.KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS, 30 * SECOND_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_TOP_APP_MS, 15 * SECOND_IN_MILLIS);
+
+        final long nowElapsed = sElapsedRealtimeClock.millis();
+        TimingSession ts = new TimingSession(nowElapsed - 5 * MINUTE_IN_MILLIS,
+                nowElapsed - 4 * MINUTE_IN_MILLIS, 2);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, ts, true);
+
+        ShrinkableDebits debit = mQuotaController.getEJDebitsLocked(SOURCE_USER_ID, SOURCE_PACKAGE);
+        assertEquals(MINUTE_IN_MILLIS, debit.getTallyLocked());
+        assertEquals(29 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        // With rewards coming in while an EJ is running, the remaining execution time should be
+        // adjusted accordingly (decrease due to EJ running + increase from reward).
+        JobStatus eJob =
+                createExpeditedJobStatus("testEJDebitTallying_RewardExceedDebits_ActiveSession", 1);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(eJob, null);
+            mQuotaController.prepareForExecutionLocked(eJob);
+        }
+        advanceElapsedClock(30 * SECOND_IN_MILLIS);
+        assertEquals(MINUTE_IN_MILLIS, debit.getTallyLocked());
+        assertEquals(28 * MINUTE_IN_MILLIS + 30 * SECOND_IN_MILLIS,
+                mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(30 * SECOND_IN_MILLIS);
+        UsageEvents.Event event =
+                new UsageEvents.Event(UsageEvents.Event.USER_INTERACTION, sSystemClock.millis());
+        event.mPackage = SOURCE_PACKAGE;
+        mUsageEventListener.onUsageEvent(SOURCE_USER_ID, event);
+        waitForNonDelayedMessagesProcessed();
+        assertEquals(0, debit.getTallyLocked());
+        assertEquals(29 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(MINUTE_IN_MILLIS);
+        assertEquals(0, debit.getTallyLocked());
+        assertEquals(28 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        // Activity start shouldn't reduce tally, but duration with activity started should affect
+        // remaining EJ time.
+        event = new UsageEvents.Event(UsageEvents.Event.ACTIVITY_RESUMED, sSystemClock.millis());
+        event.mPackage = SOURCE_PACKAGE;
+        mUsageEventListener.onUsageEvent(SOURCE_USER_ID, event);
+        waitForNonDelayedMessagesProcessed();
+        advanceElapsedClock(30 * SECOND_IN_MILLIS);
+        assertEquals(0, debit.getTallyLocked());
+        // Decrease by 30 seconds for running EJ, increase by 15 seconds due to ongoing activity.
+        assertEquals(27 * MINUTE_IN_MILLIS + 45 * SECOND_IN_MILLIS,
+                mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+        advanceElapsedClock(30 * SECOND_IN_MILLIS);
+        assertEquals(0, debit.getTallyLocked());
+        assertEquals(27 * MINUTE_IN_MILLIS + 30 * SECOND_IN_MILLIS,
+                mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(MINUTE_IN_MILLIS);
+        assertEquals(0, debit.getTallyLocked());
+        assertEquals(27 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        event = new UsageEvents.Event(UsageEvents.Event.USER_INTERACTION, sSystemClock.millis());
+        event.mPackage = SOURCE_PACKAGE;
+        mUsageEventListener.onUsageEvent(SOURCE_USER_ID, event);
+        waitForNonDelayedMessagesProcessed();
+        assertEquals(0, debit.getTallyLocked());
+        assertEquals(28 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(MINUTE_IN_MILLIS);
+        assertEquals(0, debit.getTallyLocked());
+        assertEquals(27 * MINUTE_IN_MILLIS + 30 * SECOND_IN_MILLIS,
+                mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        // At this point, with activity pausing/stopping/destroying, since we're giving a reward,
+        // tally should remain 0, and time remaining shouldn't change since it was accounted for
+        // at every step.
+        event = new UsageEvents.Event(UsageEvents.Event.ACTIVITY_DESTROYED, sSystemClock.millis());
+        event.mPackage = SOURCE_PACKAGE;
+        mUsageEventListener.onUsageEvent(SOURCE_USER_ID, event);
+        waitForNonDelayedMessagesProcessed();
+        assertEquals(0, debit.getTallyLocked());
+        assertEquals(27 * MINUTE_IN_MILLIS + 30 * SECOND_IN_MILLIS,
+                mQuotaController.getRemainingEJExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java
index 69fe140..e0c8b09 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java
@@ -500,7 +500,7 @@
     }
 
     @Override
-    protected boolean isAntennaInfoListeningSupported() {
+    protected boolean isAntennaInfoSupported() {
         return mIsAntennaInfoListeningSupported;
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
index 66b037d..1b58e92 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
@@ -123,9 +123,10 @@
             .setPowerUsage(POWER_USAGE_HIGH)
             .setAccuracy(ProviderProperties.ACCURACY_FINE)
             .build();
+    private static final CallerIdentity PROVIDER_IDENTITY = CallerIdentity.forTest(CURRENT_USER, 1,
+            "mypackage", "attribution");
     private static final CallerIdentity IDENTITY = CallerIdentity.forTest(CURRENT_USER, 1,
-            "mypackage",
-            "attribution");
+            "mypackage", "attribution", "listener");
     private static final WorkSource WORK_SOURCE = new WorkSource(IDENTITY.getUid());
 
     private Random mRandom;
@@ -169,7 +170,7 @@
         mPassive.startManager();
         mPassive.setRealProvider(new PassiveLocationProvider(mContext));
 
-        mProvider = new TestProvider(PROPERTIES, IDENTITY);
+        mProvider = new TestProvider(PROPERTIES, PROVIDER_IDENTITY);
         mProvider.setProviderAllowed(true);
 
         mManager = new LocationProviderManager(mContext, mInjector, eventLog, NAME, mPassive);
@@ -351,7 +352,8 @@
 
     @Test
     public void testGetLastLocation_ClearOnMockRemoval() {
-        MockLocationProvider mockProvider = new MockLocationProvider(PROPERTIES, IDENTITY);
+        MockLocationProvider mockProvider = new MockLocationProvider(PROPERTIES, PROVIDER_IDENTITY,
+                Collections.emptySet());
         mockProvider.setAllowed(true);
         mManager.setMockProvider(mockProvider);
 
@@ -441,7 +443,7 @@
     @Test
     public void testRegisterListener_SameProcess() throws Exception {
         CallerIdentity identity = CallerIdentity.forTest(CURRENT_USER, Process.myPid(), "mypackage",
-                "attribution");
+                "attribution", "listener");
 
         ILocationListener listener = createMockLocationListener();
         mManager.registerLocationRequest(
@@ -477,7 +479,7 @@
     @Test
     public void testRegisterListener_Unregister_SameProcess() throws Exception {
         CallerIdentity identity = CallerIdentity.forTest(CURRENT_USER, Process.myPid(), "mypackage",
-                "attribution");
+                "attribution", "listener");
 
         ILocationListener listener = createMockLocationListener();
         mManager.registerLocationRequest(
@@ -604,7 +606,7 @@
     @Test
     public void testRegisterListener_Wakelock() throws Exception {
         CallerIdentity identity = CallerIdentity.forTest(CURRENT_USER, Process.myPid(), "mypackage",
-                "attribution");
+                "attribution", "listener");
 
         ILocationListener listener = createMockLocationListener();
         mManager.registerLocationRequest(
@@ -1047,7 +1049,7 @@
         private final ArrayList<Runnable> mFlushCallbacks = new ArrayList<>();
 
         TestProvider(ProviderProperties properties, CallerIdentity identity) {
-            super(DIRECT_EXECUTOR, identity, properties);
+            super(DIRECT_EXECUTOR, identity, properties, Collections.emptySet());
         }
 
         public void setProviderAllowed(boolean allowed) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/MockableLocationProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/MockableLocationProviderTest.java
index 07170da..cf5db2e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/MockableLocationProviderTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/MockableLocationProviderTest.java
@@ -43,6 +43,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Collections;
+
 @Presubmit
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -71,7 +73,8 @@
                         .setPowerUsage(POWER_USAGE_LOW)
                         .setAccuracy(ACCURACY_FINE)
                         .build(),
-                CallerIdentity.forTest(0, 1, "testpackage", "test"));
+                CallerIdentity.forTest(0, 1, "testpackage", "test"),
+                Collections.emptySet());
 
         mProvider = new MockableLocationProvider(lock);
         mProvider.getController().setListener(mListener);
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/test/FakeProvider.java b/services/tests/mockingservicestests/src/com/android/server/location/test/FakeProvider.java
index 775bdd5..2bc1268 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/test/FakeProvider.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/test/FakeProvider.java
@@ -23,6 +23,7 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.Collections;
 
 public class FakeProvider extends AbstractLocationProvider {
 
@@ -40,7 +41,7 @@
     private final FakeProviderInterface mFakeInterface;
 
     public FakeProvider(FakeProviderInterface fakeInterface) {
-        super(Runnable::run, null, null);
+        super(Runnable::run, null, null, Collections.emptySet());
         mFakeInterface = fakeInterface;
     }
 
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index bea4ae3..68f5479 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -181,9 +181,12 @@
         ":FrameworksServicesTests_install_split_feature_a",
         ":FrameworksServicesTests_install_uses_sdk_0",
         ":FrameworksServicesTests_install_uses_sdk_q0",
-        ":FrameworksServicesTests_install_uses_sdk_r",
+        ":FrameworksServicesTests_install_uses_sdk_q0_r0",
+        ":FrameworksServicesTests_install_uses_sdk_r_none",
         ":FrameworksServicesTests_install_uses_sdk_r0",
         ":FrameworksServicesTests_install_uses_sdk_r5",
+        ":FrameworksServicesTests_install_uses_sdk_r0_s0",
+        ":FrameworksServicesTests_install_uses_sdk_r0_s5",
     ],
     out: ["FrameworkServicesTests_apks_as_resources.res.zip"],
     tools: ["soong_zip"],
diff --git a/services/tests/servicestests/apks/install_uses_sdk/Android.bp b/services/tests/servicestests/apks/install_uses_sdk/Android.bp
index feb152c..a51293d 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/Android.bp
+++ b/services/tests/servicestests/apks/install_uses_sdk/Android.bp
@@ -8,41 +8,49 @@
 }
 
 android_test_helper_app {
+    name: "FrameworksServicesTests_install_uses_sdk_q0",
+    defaults: ["FrameworksServicesTests_apks_defaults"],
+    manifest: "AndroidManifest-q0.xml",
+}
+
+android_test_helper_app {
+    name: "FrameworksServicesTests_install_uses_sdk_q0_r0",
+    defaults: ["FrameworksServicesTests_apks_defaults"],
+    manifest: "AndroidManifest-q0-r0.xml",
+}
+
+android_test_helper_app {
+    name: "FrameworksServicesTests_install_uses_sdk_r_none",
+    defaults: ["FrameworksServicesTests_apks_defaults"],
+    manifest: "AndroidManifest-r-none.xml",
+}
+
+android_test_helper_app {
     name: "FrameworksServicesTests_install_uses_sdk_r0",
     defaults: ["FrameworksServicesTests_apks_defaults"],
     manifest: "AndroidManifest-r0.xml",
-
-    srcs: ["**/*.java"],
 }
 
 android_test_helper_app {
     name: "FrameworksServicesTests_install_uses_sdk_r5",
     defaults: ["FrameworksServicesTests_apks_defaults"],
     manifest: "AndroidManifest-r5.xml",
-
-    srcs: ["**/*.java"],
 }
 
 android_test_helper_app {
-    name: "FrameworksServicesTests_install_uses_sdk_q0",
+    name: "FrameworksServicesTests_install_uses_sdk_r0_s0",
     defaults: ["FrameworksServicesTests_apks_defaults"],
-    manifest: "AndroidManifest-q0.xml",
-
-    srcs: ["**/*.java"],
+    manifest: "AndroidManifest-r0-s0.xml",
 }
 
 android_test_helper_app {
-    name: "FrameworksServicesTests_install_uses_sdk_r",
+    name: "FrameworksServicesTests_install_uses_sdk_r0_s5",
     defaults: ["FrameworksServicesTests_apks_defaults"],
-    manifest: "AndroidManifest-r.xml",
-
-    srcs: ["**/*.java"],
+    manifest: "AndroidManifest-r0-s5.xml",
 }
 
 android_test_helper_app {
     name: "FrameworksServicesTests_install_uses_sdk_0",
     defaults: ["FrameworksServicesTests_apks_defaults"],
     manifest: "AndroidManifest-0.xml",
-
-    srcs: ["**/*.java"],
 }
diff --git a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-0.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-0.xml
index 215384b..90b13d4 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-0.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-0.xml
@@ -18,7 +18,7 @@
 
     <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
         <!-- This is invalid, because there is no sdk version specified -->
-        <extension-sdk android:minExtensionVersion="5" />
+        <extension-sdk android:minExtensionVersion="0" />
     </uses-sdk>
 
     <application>
diff --git a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-q0-r0.xml
similarity index 80%
copy from services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
copy to services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-q0-r0.xml
index 5d22577..2a32276 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-q0-r0.xml
@@ -17,8 +17,9 @@
         package="com.android.frameworks.servicestests.install_uses_sdk">
 
     <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
-        <!-- This is invalid, because there is no minimum extension version specified -->
-        <extension-sdk android:sdkVersion="10000" />
+        <!-- This fails because 29 doesn't have an extension sdk -->
+        <extension-sdk android:sdkVersion="29" android:minExtensionVersion="0" />
+        <extension-sdk android:sdkVersion="30" android:minExtensionVersion="0" />
     </uses-sdk>
 
     <application>
diff --git a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r-none.xml
similarity index 94%
rename from services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
rename to services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r-none.xml
index 5d22577..c79c61c 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r-none.xml
@@ -18,7 +18,7 @@
 
     <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
         <!-- This is invalid, because there is no minimum extension version specified -->
-        <extension-sdk android:sdkVersion="10000" />
+        <extension-sdk android:sdkVersion="30" />
     </uses-sdk>
 
     <application>
diff --git a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0-s0.xml
similarity index 84%
copy from services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
copy to services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0-s0.xml
index 5d22577..af30915 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0-s0.xml
@@ -17,8 +17,8 @@
         package="com.android.frameworks.servicestests.install_uses_sdk">
 
     <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
-        <!-- This is invalid, because there is no minimum extension version specified -->
-        <extension-sdk android:sdkVersion="10000" />
+        <extension-sdk android:sdkVersion="30" android:minExtensionVersion="0" />
+        <extension-sdk android:sdkVersion="31" android:minExtensionVersion="0" />
     </uses-sdk>
 
     <application>
diff --git a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0-s5.xml
similarity index 80%
copy from services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
copy to services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0-s5.xml
index 5d22577..bafe4c4 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0-s5.xml
@@ -17,8 +17,9 @@
         package="com.android.frameworks.servicestests.install_uses_sdk">
 
     <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
-        <!-- This is invalid, because there is no minimum extension version specified -->
-        <extension-sdk android:sdkVersion="10000" />
+        <!-- This fails because 31 is not version 5 -->
+        <extension-sdk android:sdkVersion="30" android:minExtensionVersion="0" />
+        <extension-sdk android:sdkVersion="31" android:minExtensionVersion="5" />
     </uses-sdk>
 
     <application>
diff --git a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0.xml
index c1244f2..2920b86 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r0.xml
@@ -17,7 +17,7 @@
         package="com.android.frameworks.servicestests.install_uses_sdk">
 
     <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
-        <extension-sdk android:sdkVersion="10000" android:minExtensionVersion="0" />
+        <extension-sdk android:sdkVersion="30" android:minExtensionVersion="0" />
     </uses-sdk>
 
     <application>
diff --git a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r5.xml b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r5.xml
index 3410938..7723d05 100644
--- a/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r5.xml
+++ b/services/tests/servicestests/apks/install_uses_sdk/AndroidManifest-r5.xml
@@ -18,7 +18,7 @@
 
     <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="29">
         <!-- This will fail to install, because minExtensionVersion is not met -->
-        <extension-sdk android:sdkVersion="10000" android:minExtensionVersion="5" />
+        <extension-sdk android:sdkVersion="30" android:minExtensionVersion="5" />
     </uses-sdk>
 
     <application>
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
index cfa2086..f897d5c 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
@@ -160,6 +160,7 @@
     @Mock private AccessibilitySecurityPolicy mMockSecurityPolicy;
     @Mock private AccessibilityWindowManager mMockA11yWindowManager;
     @Mock private AbstractAccessibilityServiceConnection.SystemSupport mMockSystemSupport;
+    @Mock private AccessibilityTrace mMockA11yTrace;
     @Mock private WindowManagerInternal mMockWindowManagerInternal;
     @Mock private SystemActionPerformer mMockSystemActionPerformer;
     @Mock private IBinder mMockService;
@@ -188,6 +189,7 @@
         when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
         when(mMockPackageManager.hasSystemFeature(FEATURE_FINGERPRINT)).thenReturn(true);
 
+        when(mMockA11yTrace.isA11yTracingEnabled()).thenReturn(false);
         // Fake a11yWindowInfo and remote a11y connection for tests.
         addA11yWindowInfo(mA11yWindowInfos, WINDOWID, false, Display.DEFAULT_DISPLAY);
         addA11yWindowInfo(mA11yWindowInfos, PIP_WINDOWID, true, Display.DEFAULT_DISPLAY);
@@ -227,8 +229,8 @@
 
         mServiceConnection = new TestAccessibilityServiceConnection(mMockContext, COMPONENT_NAME,
                 mSpyServiceInfo, SERVICE_ID, mHandler, new Object(), mMockSecurityPolicy,
-                mMockSystemSupport, mMockWindowManagerInternal, mMockSystemActionPerformer,
-                mMockA11yWindowManager);
+                mMockSystemSupport, mMockA11yTrace, mMockWindowManagerInternal,
+                mMockSystemActionPerformer, mMockA11yWindowManager);
         // Assume that the service is connected
         mServiceConnection.mService = mMockService;
         mServiceConnection.mServiceInterface = mMockServiceInterface;
@@ -849,12 +851,13 @@
         TestAccessibilityServiceConnection(Context context, ComponentName componentName,
                 AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler,
                 Object lock, AccessibilitySecurityPolicy securityPolicy,
-                SystemSupport systemSupport, WindowManagerInternal windowManagerInternal,
+                SystemSupport systemSupport, AccessibilityTrace trace,
+                WindowManagerInternal windowManagerInternal,
                 SystemActionPerformer systemActionPerfomer,
                 AccessibilityWindowManager a11yWindowManager) {
             super(context, componentName, accessibilityServiceInfo, id, mainHandler, lock,
-                    securityPolicy, systemSupport, windowManagerInternal, systemActionPerfomer,
-                    a11yWindowManager);
+                    securityPolicy, systemSupport, trace, windowManagerInternal,
+                    systemActionPerfomer, a11yWindowManager);
             mResolvedUserId = USER_ID;
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java
index 4b2a9fc..80e81d6 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java
@@ -30,7 +30,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
@@ -51,16 +50,19 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.LocalServices;
 import com.android.server.accessibility.gestures.TouchExplorer;
 import com.android.server.accessibility.magnification.FullScreenMagnificationController;
 import com.android.server.accessibility.magnification.FullScreenMagnificationGestureHandler;
 import com.android.server.accessibility.magnification.MagnificationGestureHandler;
 import com.android.server.accessibility.magnification.WindowMagnificationGestureHandler;
+import com.android.server.wm.WindowManagerInternal;
 
 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;
 
 import java.util.ArrayList;
@@ -91,7 +93,9 @@
                     FullScreenMagnificationGestureHandler.class, TouchExplorer.class,
                     AutoclickController.class, AccessibilityInputFilter.class};
 
-    private FullScreenMagnificationController mMockFullScreenMagnificationController;
+    @Mock private WindowManagerInternal.AccessibilityControllerInternal mMockA11yController;
+    @Mock private WindowManagerInternal mMockWindowManagerService;
+    @Mock private FullScreenMagnificationController mMockFullScreenMagnificationController;
     private AccessibilityManagerService mAms;
     private AccessibilityInputFilter mA11yInputFilter;
     private EventCaptor mCaptor1;
@@ -134,16 +138,21 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         Context context = InstrumentationRegistry.getContext();
+        LocalServices.removeServiceForTest(WindowManagerInternal.class);
+        LocalServices.addService(
+                WindowManagerInternal.class, mMockWindowManagerService);
+        when(mMockWindowManagerService.getAccessibilityController()).thenReturn(
+                mMockA11yController);
+        when(mMockA11yController.isAccessibilityTracingEnabled()).thenReturn(false);
 
         setDisplayCount(1);
         mAms = spy(new AccessibilityManagerService(context));
-        mMockFullScreenMagnificationController = mock(FullScreenMagnificationController.class);
         mA11yInputFilter = new AccessibilityInputFilter(context, mAms, mEventHandler);
         mA11yInputFilter.onInstalled();
 
-        when(mAms.getValidDisplayList()).thenReturn(mDisplayList);
-        when(mAms.getFullScreenMagnificationController()).thenReturn(
-                mMockFullScreenMagnificationController);
+        doReturn(mDisplayList).when(mAms).getValidDisplayList();
+        doReturn(mMockFullScreenMagnificationController).when(mAms)
+                .getFullScreenMagnificationController();
     }
 
     @After
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index 110bb21..bcc756a 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -84,6 +84,7 @@
     @Mock private AccessibilityServiceInfo mMockServiceInfo;
     @Mock private ResolveInfo mMockResolveInfo;
     @Mock private AbstractAccessibilityServiceConnection.SystemSupport mMockSystemSupport;
+    @Mock private WindowManagerInternal.AccessibilityControllerInternal mMockA11yController;
     @Mock private PackageManager mMockPackageManager;
     @Mock private WindowManagerInternal mMockWindowManagerService;
     @Mock private AccessibilitySecurityPolicy mMockSecurityPolicy;
@@ -115,6 +116,9 @@
 
         when(mMockMagnificationController.getWindowMagnificationMgr()).thenReturn(
                 mMockWindowMagnificationMgr);
+        when(mMockWindowManagerService.getAccessibilityController()).thenReturn(
+                mMockA11yController);
+        when(mMockA11yController.isAccessibilityTracingEnabled()).thenReturn(false);
         mA11yms = new AccessibilityManagerService(
             InstrumentationRegistry.getContext(),
             mMockPackageManager,
@@ -153,6 +157,7 @@
                 new Object(),
                 mMockSecurityPolicy,
                 mMockSystemSupport,
+                mA11yms,
                 mMockWindowManagerService,
                 mMockSystemActionPerformer,
                 mMockA11yWindowManager,
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
index 6963a1a..00daa5c 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
@@ -85,6 +85,7 @@
     @Mock AccessibilityWindowManager mMockA11yWindowManager;
     @Mock ActivityTaskManagerInternal mMockActivityTaskManagerInternal;
     @Mock AbstractAccessibilityServiceConnection.SystemSupport mMockSystemSupport;
+    @Mock AccessibilityTrace mMockA11yTrace;
     @Mock WindowManagerInternal mMockWindowManagerInternal;
     @Mock SystemActionPerformer mMockSystemActionPerformer;
     @Mock KeyEventDispatcher mMockKeyEventDispatcher;
@@ -110,12 +111,13 @@
         mMockResolveInfo.serviceInfo.applicationInfo = mock(ApplicationInfo.class);
 
         when(mMockIBinder.queryLocalInterface(any())).thenReturn(mMockServiceClient);
+        when(mMockA11yTrace.isA11yTracingEnabled()).thenReturn(false);
 
         mConnection = new AccessibilityServiceConnection(mMockUserState, mMockContext,
                 COMPONENT_NAME, mMockServiceInfo, SERVICE_ID, mHandler, new Object(),
-                mMockSecurityPolicy, mMockSystemSupport, mMockWindowManagerInternal,
-                mMockSystemActionPerformer, mMockA11yWindowManager,
-                mMockActivityTaskManagerInternal);
+                mMockSecurityPolicy, mMockSystemSupport, mMockA11yTrace,
+                mMockWindowManagerInternal, mMockSystemActionPerformer,
+                mMockA11yWindowManager, mMockActivityTaskManagerInternal);
         when(mMockSecurityPolicy.canPerformGestures(mConnection)).thenReturn(true);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
index 8062bfe..1603087 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
@@ -63,6 +63,7 @@
     @Mock AccessibilitySecurityPolicy mMockSecurityPolicy;
     @Mock AccessibilityWindowManager mMockA11yWindowManager;
     @Mock AbstractAccessibilityServiceConnection.SystemSupport mMockSystemSupport;
+    @Mock AccessibilityTrace mMockA11yTrace;
     @Mock WindowManagerInternal mMockWindowManagerInternal;
     @Mock SystemActionPerformer mMockSystemActionPerformer;
     @Mock IBinder mMockOwner;
@@ -80,6 +81,7 @@
         mMockResolveInfo.serviceInfo.applicationInfo = mock(ApplicationInfo.class);
 
         when(mMockAccessibilityServiceClient.asBinder()).thenReturn(mMockServiceAsBinder);
+        when(mMockA11yTrace.isA11yTracingEnabled()).thenReturn(false);
 
         final Context context = getInstrumentation().getTargetContext();
         when(mMockContext.getSystemService(Context.DISPLAY_SERVICE)).thenReturn(
@@ -197,7 +199,7 @@
     private void register(int flags) {
         mUiAutomationManager.registerUiTestAutomationServiceLocked(mMockOwner,
                 mMockAccessibilityServiceClient, mMockContext, mMockServiceInfo, SERVICE_ID,
-                mMessageCapturingHandler, mMockSecurityPolicy, mMockSystemSupport,
+                mMessageCapturingHandler, mMockSecurityPolicy, mMockSystemSupport, mMockA11yTrace,
                 mMockWindowManagerInternal, mMockSystemActionPerformer,
                 mMockA11yWindowManager, flags);
     }
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationGesturesObserverTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationGesturesObserverTest.java
index 895fb17..5dbf837 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationGesturesObserverTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationGesturesObserverTest.java
@@ -69,7 +69,7 @@
         mContext = InstrumentationRegistry.getContext();
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
         mObserver = new MagnificationGesturesObserver(mCallback, new SimpleSwipe(mContext),
-                new TwoFingersDown(mContext));
+                new TwoFingersDownOrSwipe(mContext));
     }
 
     @Test
@@ -77,9 +77,7 @@
         final MotionEvent moveEvent = TouchEventGenerator.moveEvent(Display.DEFAULT_DISPLAY,
                 DEFAULT_X , DEFAULT_Y);
 
-        mInstrumentation.runOnMainSync(() -> {
-            mObserver.onMotionEvent(moveEvent, moveEvent, 0);
-        });
+        mObserver.onMotionEvent(moveEvent, moveEvent, 0);
 
         verify(mCallback).onGestureCancelled(eq(0L),
                 mEventInfoArgumentCaptor.capture(), argThat(new MotionEventMatcher(moveEvent)));
@@ -92,9 +90,7 @@
         final MotionEvent downEvent = TouchEventGenerator.downEvent(Display.DEFAULT_DISPLAY,
                 DEFAULT_X , DEFAULT_Y);
 
-        mInstrumentation.runOnMainSync(() -> {
-            mObserver.onMotionEvent(downEvent, downEvent, 0);
-        });
+        mObserver.onMotionEvent(downEvent, downEvent, 0);
 
         verify(mCallback).onGestureCancelled(eq(0L),
                 mEventInfoArgumentCaptor.capture(), argThat(new MotionEventMatcher(downEvent)));
@@ -108,9 +104,7 @@
         final int timeoutMillis = MagnificationGestureMatcher.getMagnificationMultiTapTimeout(
                 mContext) + 100;
 
-        mInstrumentation.runOnMainSync(() -> {
-            mObserver.onMotionEvent(downEvent, downEvent, 0);
-        });
+        mObserver.onMotionEvent(downEvent, downEvent, 0);
 
         verify(mCallback, timeout(timeoutMillis)).onGestureCancelled(eq(downEvent.getDownTime()),
                 mEventInfoArgumentCaptor.capture(), argThat(new MotionEventMatcher(downEvent)));
@@ -121,14 +115,12 @@
     public void sendEventsOfSwiping_onGestureCompleted() {
         final MotionEvent downEvent = TouchEventGenerator.downEvent(Display.DEFAULT_DISPLAY,
                 DEFAULT_X, DEFAULT_Y);
-        final float swipeDistance = ViewConfiguration.get(mContext).getScaledTouchSlop();
+        final float swipeDistance = ViewConfiguration.get(mContext).getScaledTouchSlop() + 1;
         final MotionEvent moveEvent = TouchEventGenerator.moveEvent(Display.DEFAULT_DISPLAY,
                 DEFAULT_X + swipeDistance, DEFAULT_Y + swipeDistance);
 
-        mInstrumentation.runOnMainSync(() -> {
-            mObserver.onMotionEvent(downEvent, downEvent, 0);
-            mObserver.onMotionEvent(moveEvent, moveEvent, 0);
-        });
+        mObserver.onMotionEvent(downEvent, downEvent, 0);
+        mObserver.onMotionEvent(moveEvent, moveEvent, 0);
 
         verify(mCallback).onGestureCompleted(eq(MagnificationGestureMatcher.GESTURE_SWIPE),
                 eq(downEvent.getDownTime()), mEventInfoArgumentCaptor.capture(),
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/SimpleSwipeTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/SimpleSwipeTest.java
index 01631bf21..0ca631e 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/SimpleSwipeTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/SimpleSwipeTest.java
@@ -78,7 +78,7 @@
 
     @Test
     public void sendSwipeEvent_onGestureCompleted() {
-        final float swipeDistance = ViewConfiguration.get(mContext).getScaledTouchSlop();
+        final float swipeDistance = ViewConfiguration.get(mContext).getScaledTouchSlop() + 1;
         final MotionEvent downEvent = TouchEventGenerator.downEvent(Display.DEFAULT_DISPLAY,
                 DEFAULT_X, DEFAULT_Y);
         final MotionEvent moveEvent = TouchEventGenerator.moveEvent(Display.DEFAULT_DISPLAY,
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownOrSwipeTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownOrSwipeTest.java
new file mode 100644
index 0000000..162d2a9
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownOrSwipeTest.java
@@ -0,0 +1,146 @@
+/*
+ * 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.accessibility.magnification;
+
+import static com.android.server.accessibility.utils.TouchEventGenerator.movePointer;
+import static com.android.server.accessibility.utils.TouchEventGenerator.twoPointersDownEvents;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.after;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.graphics.PointF;
+import android.view.Display;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.server.accessibility.utils.TouchEventGenerator;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.List;
+
+/**
+ * Tests for {@link TwoFingersDownOrSwipe}.
+ */
+public class TwoFingersDownOrSwipeTest {
+
+    private static final float DEFAULT_X = 100f;
+    private static final float DEFAULT_Y = 100f;
+
+    private static float sSwipeMinDistance;
+    private static int sTimeoutMillis;
+    private static Context sContext;
+
+    private GesturesObserver mGesturesObserver;
+    @Mock
+    private GesturesObserver.Listener mListener;
+
+    @BeforeClass
+    public static void setupOnce() {
+        sContext = InstrumentationRegistry.getContext();
+        sTimeoutMillis = MagnificationGestureMatcher.getMagnificationMultiTapTimeout(
+                sContext) + 100;
+        sSwipeMinDistance = ViewConfiguration.get(sContext).getScaledTouchSlop() + 1;
+    }
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mGesturesObserver = new GesturesObserver(mListener, new TwoFingersDownOrSwipe(sContext));
+    }
+
+    @Test
+    public void sendSingleDownEvent_GestureCanceledAfterTimeout() {
+        final MotionEvent downEvent = TouchEventGenerator.downEvent(Display.DEFAULT_DISPLAY,
+                DEFAULT_X, DEFAULT_Y);
+
+        mGesturesObserver.onMotionEvent(downEvent, downEvent, 0);
+
+        verify(mListener, timeout(sTimeoutMillis)).onGestureCancelled(any(MotionEvent.class),
+                any(MotionEvent.class), eq(0));
+    }
+
+    @Test
+    public void sendTwoFingerDownEvent_onGestureCompleted() {
+        final List<MotionEvent> downEvents = twoPointersDownEvents(Display.DEFAULT_DISPLAY,
+                new PointF(DEFAULT_X, DEFAULT_Y), new PointF(DEFAULT_X + 10, DEFAULT_Y + 10));
+
+        for (MotionEvent event : downEvents) {
+            mGesturesObserver.onMotionEvent(event, event, 0);
+        }
+
+        verify(mListener, timeout(sTimeoutMillis)).onGestureCompleted(
+                MagnificationGestureMatcher.GESTURE_TWO_FINGERS_DOWN_OR_SWIPE, downEvents.get(1),
+                downEvents.get(1), 0);
+    }
+
+    @Test
+    public void sendSingleTapEvent_onGestureCancelled() {
+        final MotionEvent downEvent = TouchEventGenerator.downEvent(Display.DEFAULT_DISPLAY,
+                DEFAULT_X, DEFAULT_Y);
+        final MotionEvent upEvent = TouchEventGenerator.upEvent(Display.DEFAULT_DISPLAY,
+                DEFAULT_X, DEFAULT_Y);
+
+        mGesturesObserver.onMotionEvent(downEvent, downEvent, 0);
+        mGesturesObserver.onMotionEvent(upEvent, upEvent, 0);
+
+        verify(mListener, after(ViewConfiguration.getDoubleTapTimeout())).onGestureCancelled(
+                any(MotionEvent.class), any(MotionEvent.class), eq(0));
+    }
+
+    @Test
+    public void firstPointerMove_twoPointersDown_onGestureCompleted() {
+        final List<MotionEvent> downEvents = twoPointersDownEvents(Display.DEFAULT_DISPLAY,
+                new PointF(DEFAULT_X, DEFAULT_Y), new PointF(DEFAULT_X + 10, DEFAULT_Y + 10));
+        for (MotionEvent event : downEvents) {
+            mGesturesObserver.onMotionEvent(event, event, 0);
+        }
+        final MotionEvent moveEvent = movePointer(downEvents.get(1), 0, sSwipeMinDistance, 0);
+
+        mGesturesObserver.onMotionEvent(moveEvent, moveEvent, 0);
+
+        verify(mListener).onGestureCompleted(
+                MagnificationGestureMatcher.GESTURE_TWO_FINGERS_DOWN_OR_SWIPE, moveEvent,
+                moveEvent, 0);
+    }
+
+    @Test
+    public void secondPointerMove_twoPointersDown_onGestureCompleted() {
+        final List<MotionEvent> downEvents = twoPointersDownEvents(Display.DEFAULT_DISPLAY,
+                new PointF(DEFAULT_X, DEFAULT_Y), new PointF(DEFAULT_X + 10, DEFAULT_Y + 10));
+        for (MotionEvent event : downEvents) {
+            mGesturesObserver.onMotionEvent(event, event, 0);
+        }
+        final MotionEvent moveEvent = movePointer(downEvents.get(1), 1, sSwipeMinDistance, 0);
+
+        mGesturesObserver.onMotionEvent(moveEvent, moveEvent, 0);
+
+        verify(mListener).onGestureCompleted(
+                MagnificationGestureMatcher.GESTURE_TWO_FINGERS_DOWN_OR_SWIPE, moveEvent,
+                moveEvent, 0);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownTest.java
deleted file mode 100644
index ed8dc4e..0000000
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/TwoFingersDownTest.java
+++ /dev/null
@@ -1,114 +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.accessibility.magnification;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.view.Display;
-import android.view.MotionEvent;
-
-import androidx.test.InstrumentationRegistry;
-
-import com.android.server.accessibility.utils.TouchEventGenerator;
-
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/**
- * Tests for {@link TwoFingersDown}.
- */
-public class TwoFingersDownTest {
-
-    private static final float DEFAULT_X = 100f;
-    private static final float DEFAULT_Y = 100f;
-
-    private static Context sContext;
-    private static int sTimeoutMillis;
-
-    private Context mContext;
-    private GesturesObserver mGesturesObserver;
-    @Mock
-    private GesturesObserver.Listener mListener;
-
-    @BeforeClass
-    public static void setupOnce() {
-        sContext = InstrumentationRegistry.getContext();
-        sTimeoutMillis = MagnificationGestureMatcher.getMagnificationMultiTapTimeout(
-                sContext) + 100;
-    }
-
-    @Before
-    public void setUp() {
-        mContext = InstrumentationRegistry.getContext();
-        MockitoAnnotations.initMocks(this);
-        mGesturesObserver = new GesturesObserver(mListener, new TwoFingersDown(mContext));
-    }
-
-    @Test
-    public void sendSingleDownEvent_GestureCanceledAfterTimeout() {
-        final MotionEvent downEvent = TouchEventGenerator.downEvent(Display.DEFAULT_DISPLAY,
-                DEFAULT_X, DEFAULT_Y);
-
-        mGesturesObserver.onMotionEvent(downEvent, downEvent, 0);
-
-        verify(mListener, timeout(sTimeoutMillis)).onGestureCancelled(any(MotionEvent.class),
-                any(MotionEvent.class), eq(0));
-    }
-
-    @Test
-    public void sendTwoFingerDownEvent_onGestureCompleted() {
-        final MotionEvent downEvent = TouchEventGenerator.downEvent(Display.DEFAULT_DISPLAY,
-                DEFAULT_X, DEFAULT_Y);
-        final MotionEvent.PointerCoords defPointerCoords = new MotionEvent.PointerCoords();
-        defPointerCoords.x = DEFAULT_X;
-        defPointerCoords.y = DEFAULT_Y;
-        final MotionEvent.PointerCoords secondPointerCoords = new MotionEvent.PointerCoords();
-        secondPointerCoords.x = DEFAULT_X + 10;
-        secondPointerCoords.y = DEFAULT_Y + 10;
-
-        final MotionEvent twoPointersDownEvent = TouchEventGenerator.twoPointersDownEvent(
-                Display.DEFAULT_DISPLAY, defPointerCoords, secondPointerCoords);
-
-        mGesturesObserver.onMotionEvent(downEvent, downEvent, 0);
-        mGesturesObserver.onMotionEvent(twoPointersDownEvent, twoPointersDownEvent, 0);
-
-        verify(mListener, timeout(sTimeoutMillis)).onGestureCompleted(
-                MagnificationGestureMatcher.GESTURE_TWO_FINGER_DOWN, twoPointersDownEvent,
-                twoPointersDownEvent, 0);
-    }
-
-    @Test
-    public void sendSingleTapEvent_onGestureCancelled() {
-        final MotionEvent downEvent = TouchEventGenerator.downEvent(Display.DEFAULT_DISPLAY,
-                DEFAULT_X, DEFAULT_Y);
-        final MotionEvent upEvent = TouchEventGenerator.upEvent(Display.DEFAULT_DISPLAY,
-                DEFAULT_X, DEFAULT_Y);
-
-        mGesturesObserver.onMotionEvent(downEvent, downEvent, 0);
-        mGesturesObserver.onMotionEvent(upEvent, upEvent, 0);
-
-        verify(mListener, timeout(sTimeoutMillis)).onGestureCancelled(any(MotionEvent.class),
-                any(MotionEvent.class), eq(0));
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
index 4b7ebbc..b9498d6 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
@@ -24,13 +24,15 @@
 import static org.mockito.Mockito.verify;
 
 import android.content.Context;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.RemoteException;
 import android.util.DebugUtils;
 import android.view.InputDevice;
 import android.view.MotionEvent;
+import android.view.ViewConfiguration;
 
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.accessibility.EventStreamTransformation;
@@ -43,6 +45,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.List;
 import java.util.function.IntConsumer;
 
 /**
@@ -75,7 +78,7 @@
     @Before
     public void setUp() throws RemoteException {
         MockitoAnnotations.initMocks(this);
-        mContext = InstrumentationRegistry.getContext();
+        mContext = InstrumentationRegistry.getInstrumentation().getContext();
         mWindowMagnificationManager = new WindowMagnificationManager(mContext, 0,
                 mock(WindowMagnificationManager.Callback.class));
         mMockConnection = new MockWindowMagnificationConnection();
@@ -100,8 +103,8 @@
      * Covers following paths to get to and back between each state and {@link #STATE_IDLE}.
      * <p>
      *     <br> IDLE -> SHOW_MAGNIFIER [label="a11y\nbtn"]
-     *     <br> SHOW_MAGNIFIER -> TWO_FINGER_DOWN [label="2hold"]
-     *     <br> TWO_FINGER_DOWN -> SHOW_MAGNIFIER [label="release"]
+     *     <br> SHOW_MAGNIFIER -> TWO_FINGERS_DOWN [label="2hold"]
+     *     <br> TWO_FINGERS_DOWN -> SHOW_MAGNIFIER [label="release"]
      *     <br> SHOW_MAGNIFIER -> IDLE [label="a11y\nbtn"]
      *     <br> IDLE -> SHOW_MAGNIFIER_TRIPLE_TAP [label="3tap"]
      *     <br> SHOW_MAGNIFIER_TRIPLE_TAP -> IDLE [label="3tap"]
@@ -112,18 +115,16 @@
      */
     @Test
     public void testEachState_isReachableAndRecoverable() {
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
-            forEachState(state -> {
-                goFromStateIdleTo(state);
-                assertIn(state);
-                returnToNormalFrom(state);
-                try {
-                    assertIn(STATE_IDLE);
-                } catch (AssertionError e) {
-                    throw new AssertionError("Failed while testing state " + stateToString(state),
-                            e);
-                }
-            });
+        forEachState(state -> {
+            goFromStateIdleTo(state);
+            assertIn(state);
+            returnToNormalFrom(state);
+            try {
+                assertIn(STATE_IDLE);
+            } catch (AssertionError e) {
+                throw new AssertionError("Failed while testing state " + stateToString(state),
+                        e);
+            }
         });
     }
 
@@ -209,10 +210,19 @@
                 case STATE_TWO_FINGERS_DOWN: {
                     goFromStateIdleTo(STATE_SHOW_MAGNIFIER_SHORTCUT);
                     final Rect frame = mMockConnection.getMirrorWindowFrame();
-                    send(downEvent(frame.centerX(), frame.centerY()));
-                    //Second finger is outside the window.
-                    send(twoPointerDownEvent(new float[]{frame.centerX(), frame.centerX() + 10},
-                            new float[]{frame.centerY(), frame.centerY() + 10}));
+                    final PointF firstPointerDown = new PointF(frame.centerX(), frame.centerY());
+                    // The second finger is outside the window.
+                    final PointF secondPointerDown = new PointF(frame.right + 10,
+                            frame.bottom + 10);
+                    final List<MotionEvent> motionEvents =
+                            TouchEventGenerator.twoPointersDownEvents(DISPLAY_0,
+                                    firstPointerDown, secondPointerDown);
+                    for (MotionEvent downEvent: motionEvents) {
+                        send(downEvent);
+                    }
+                    // Wait for two-finger down gesture completed.
+                    Thread.sleep(ViewConfiguration.getDoubleTapTimeout());
+                    InstrumentationRegistry.getInstrumentation().waitForIdleSync();
                 }
                 break;
                 case STATE_SHOW_MAGNIFIER_TRIPLE_TAP: {
@@ -301,16 +311,6 @@
         send(upEvent(DEFAULT_TAP_X, DEFAULT_TAP_Y));
     }
 
-    private MotionEvent twoPointerDownEvent(float[] x, float[] y) {
-        final MotionEvent.PointerCoords defPointerCoords = new MotionEvent.PointerCoords();
-        defPointerCoords.x = x[0];
-        defPointerCoords.y = y[0];
-        final MotionEvent.PointerCoords pointerCoords = new MotionEvent.PointerCoords();
-        pointerCoords.x = x[1];
-        pointerCoords.y = y[1];
-        return TouchEventGenerator.twoPointersDownEvent(DISPLAY_0, defPointerCoords, pointerCoords);
-    }
-
     private String stateDump() {
         return "\nCurrent state dump:\n" + mWindowMagnificationGestureHandler.mCurrentState;
     }
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java b/services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java
index a05881f..fbcde53 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/utils/TouchEventGenerator.java
@@ -19,16 +19,19 @@
 import static android.view.MotionEvent.ACTION_DOWN;
 import static android.view.MotionEvent.ACTION_MOVE;
 import static android.view.MotionEvent.ACTION_POINTER_DOWN;
+import static android.view.MotionEvent.ACTION_POINTER_UP;
 import static android.view.MotionEvent.ACTION_UP;
-import static android.view.MotionEvent.PointerCoords;
 
+import android.graphics.PointF;
 import android.os.SystemClock;
 import android.view.InputDevice;
 import android.view.MotionEvent;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * generates {@link MotionEvent} with source {@link InputDevice#SOURCE_TOUCHSCREEN}
- *
  */
 public class TouchEventGenerator {
 
@@ -39,44 +42,68 @@
     public static MotionEvent moveEvent(int displayId, float x, float y) {
         return generateSingleTouchEvent(displayId, ACTION_MOVE, x, y);
     }
+
     public static MotionEvent upEvent(int displayId, float x, float y) {
         return generateSingleTouchEvent(displayId, ACTION_UP, x, y);
     }
 
-    public static MotionEvent twoPointersDownEvent(int displayId, PointerCoords defPointerCoords,
-            PointerCoords pointerCoords) {
-        return generateTwoPointersEvent(displayId, ACTION_POINTER_DOWN, defPointerCoords,
-                pointerCoords);
-    }
-
     private static MotionEvent generateSingleTouchEvent(int displayId, int action, float x,
             float y) {
-        final long  downTime = SystemClock.uptimeMillis();
-        final MotionEvent ev = MotionEvent.obtain(downTime, downTime,
-                action, x, y, 0);
-        ev.setDisplayId(displayId);
-        ev.setSource(InputDevice.SOURCE_TOUCHSCREEN);
-        return ev;
+        return generateMultiplePointersEvent(displayId, action, new PointF(x, y));
     }
 
-    private static MotionEvent generateTwoPointersEvent(int displayId, int action,
-            PointerCoords defPointerCoords, PointerCoords pointerCoords) {
-        final long  downTime = SystemClock.uptimeMillis();
-        MotionEvent.PointerProperties defPointerProperties = new MotionEvent.PointerProperties();
-        defPointerProperties.id = 0;
-        defPointerProperties.toolType = MotionEvent.TOOL_TYPE_FINGER;
-        MotionEvent.PointerProperties pointerProperties = new MotionEvent.PointerProperties();
-        pointerProperties.id = 1;
-        pointerProperties.toolType = MotionEvent.TOOL_TYPE_FINGER;
+    /**
+     * Creates a list of {@link MotionEvent} with given pointers location.
+     *
+     * @param displayId the display id
+     * @param pointF1   location on the screen of the second pointer.
+     * @param pointF2   location on the screen of the second pointer.
+     * @return a list of {@link MotionEvent} with {@link MotionEvent#ACTION_DOWN} and {@link
+     * MotionEvent#ACTION_POINTER_DOWN}.
+     */
+    public static List<MotionEvent> twoPointersDownEvents(int displayId, PointF pointF1,
+            PointF pointF2) {
+        final List<MotionEvent> downEvents = new ArrayList<>();
+        final MotionEvent downEvent = generateMultiplePointersEvent(displayId,
+                MotionEvent.ACTION_DOWN, pointF1);
+        downEvents.add(downEvent);
 
+        final int actionIndex = 1 << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+        final int action = ACTION_POINTER_DOWN | actionIndex;
+
+        final MotionEvent twoPointersDownEvent = generateMultiplePointersEvent(displayId, action,
+                pointF1, pointF2);
+        downEvents.add(twoPointersDownEvent);
+        return downEvents;
+    }
+
+    private static MotionEvent generateMultiplePointersEvent(int displayId, int action,
+            PointF... pointFs) {
+        final int length = pointFs.length;
+        final MotionEvent.PointerCoords[] pointerCoordsArray =
+                new MotionEvent.PointerCoords[length];
+        final MotionEvent.PointerProperties[] pointerPropertiesArray =
+                new MotionEvent.PointerProperties[length];
+        for (int i = 0; i < length; i++) {
+            MotionEvent.PointerCoords pointerCoords = new MotionEvent.PointerCoords();
+            pointerCoords.x = pointFs[i].x;
+            pointerCoords.y = pointFs[i].y;
+            pointerCoordsArray[i] = pointerCoords;
+
+            MotionEvent.PointerProperties pointerProperties = new MotionEvent.PointerProperties();
+            pointerProperties.id = i;
+            pointerProperties.toolType = MotionEvent.TOOL_TYPE_FINGER;
+            pointerPropertiesArray[i] = pointerProperties;
+        }
+
+        final long downTime = SystemClock.uptimeMillis();
         final MotionEvent ev = MotionEvent.obtain(
                 /* downTime */ downTime,
                 /* eventTime */ downTime,
                 /* action */ action,
-                /* pointerCount */ 2,
-                /* pointerProperties */ new MotionEvent.PointerProperties[] {
-                        defPointerProperties, pointerProperties},
-                /* pointerCoords */ new PointerCoords[] { defPointerCoords, pointerCoords },
+                /* pointerCount */ length,
+                /* pointerProperties */ pointerPropertiesArray,
+                /* pointerCoords */ pointerCoordsArray,
                 /* metaState */ 0,
                 /* buttonState */ 0,
                 /* xPrecision */ 1.0f,
@@ -88,4 +115,65 @@
         ev.setDisplayId(displayId);
         return ev;
     }
+
+    /**
+     *  Generates a move event that moves the pointer of the original event with given index.
+     *  The original event should not be up event and we don't support
+     *  {@link MotionEvent#ACTION_POINTER_UP} now.
+     *
+     * @param originalEvent the move or down event
+     * @param pointerIndex the index of the pointer we want to move.
+     * @param offsetX the offset in X coordinate.
+     * @param offsetY the offset in Y coordinate.
+     * @return a motion event with move action.
+     */
+    public static MotionEvent movePointer(MotionEvent originalEvent, int pointerIndex,
+            float offsetX, float offsetY) {
+        if (originalEvent.getActionMasked() == ACTION_UP) {
+            throw new IllegalArgumentException("No pointer is on the screen");
+        }
+
+        if (originalEvent.getActionMasked() == ACTION_POINTER_UP) {
+            throw new IllegalArgumentException("unsupported yet,please implement it first");
+        }
+
+        final int pointerCount = originalEvent.getPointerCount();
+        if (pointerIndex >= pointerCount) {
+            throw new IllegalArgumentException(
+                    pointerIndex + "is not available with pointer count" + pointerCount);
+        }
+        final int action = MotionEvent.ACTION_MOVE;
+        final MotionEvent.PointerProperties[] pp = new MotionEvent.PointerProperties[pointerCount];
+        for (int i = 0; i < pointerCount; i++) {
+            MotionEvent.PointerProperties pointerProperty = new MotionEvent.PointerProperties();
+            originalEvent.getPointerProperties(i, pointerProperty);
+            pp[i] = pointerProperty;
+        }
+
+        final MotionEvent.PointerCoords[] pc = new MotionEvent.PointerCoords[pointerCount];
+        for (int i = 0; i < pointerCount; i++) {
+            MotionEvent.PointerCoords pointerCoord = new MotionEvent.PointerCoords();
+            originalEvent.getPointerCoords(i, pointerCoord);
+            pc[i] = pointerCoord;
+        }
+        pc[pointerIndex].x += offsetX;
+        pc[pointerIndex].y += offsetY;
+        final MotionEvent ev = MotionEvent.obtain(
+                /* downTime */ originalEvent.getDownTime(),
+                /* eventTime */ SystemClock.uptimeMillis(),
+                /* action */ action,
+                /* pointerCount */ 2,
+                /* pointerProperties */ pp,
+                /* pointerCoords */ pc,
+                /* metaState */ 0,
+                /* buttonState */ 0,
+                /* xPrecision */ 1.0f,
+                /* yPrecision */ 1.0f,
+                /* deviceId */ 0,
+                /* edgeFlags */ 0,
+                /* source */ originalEvent.getSource(),
+                /* flags */ originalEvent.getFlags());
+        ev.setDisplayId(originalEvent.getDisplayId());
+        return ev;
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/am/BatteryStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/am/BatteryStatsServiceTest.java
index 488e5cd..1870df9 100644
--- a/services/tests/servicestests/src/com/android/server/am/BatteryStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/BatteryStatsServiceTest.java
@@ -30,6 +30,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -59,6 +60,7 @@
     }
 
     @Test
+    @Ignore("b/180015146")
     public void testAwaitCompletion() throws Exception {
         final CountDownLatch readyLatch = new CountDownLatch(2);
         final CountDownLatch startLatch = new CountDownLatch(1);
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
index 73b0105..6890ed1 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
@@ -28,6 +28,7 @@
 import android.app.appsearch.SetSchemaResponse;
 import android.app.appsearch.exceptions.AppSearchException;
 import android.content.Context;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 
 import androidx.test.core.app.ApplicationProvider;
@@ -55,6 +56,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 public class AppSearchImplTest {
@@ -971,21 +973,46 @@
     }
 
     @Test
-    public void testHasSchemaType() throws Exception {
-        // Nothing exists yet
-        assertThat(mAppSearchImpl.hasSchemaTypeLocked("package", "database", "Schema")).isFalse();
+    public void testGetPackageToDatabases() throws Exception {
+        Map<String, Set<String>> existingMapping = mAppSearchImpl.getPackageToDatabases();
+        Map<String, Set<String>> expectedMapping = new ArrayMap<>();
+        expectedMapping.putAll(existingMapping);
 
+        // Has database1
+        expectedMapping.put("package1", ImmutableSet.of("database1"));
         mAppSearchImpl.setSchema(
-                "package",
-                "database",
-                Collections.singletonList(new AppSearchSchema.Builder("Schema").build()),
+                "package1",
+                "database1",
+                Collections.singletonList(new AppSearchSchema.Builder("schema").build()),
                 /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
                 /*schemasPackageAccessible=*/ Collections.emptyMap(),
                 /*forceOverride=*/ false);
-        assertThat(mAppSearchImpl.hasSchemaTypeLocked("package", "database", "Schema")).isTrue();
+        assertThat(mAppSearchImpl.getPackageToDatabases())
+                .containsExactlyEntriesIn(expectedMapping);
 
-        assertThat(mAppSearchImpl.hasSchemaTypeLocked("package", "database", "UnknownSchema"))
-                .isFalse();
+        // Has both databases
+        expectedMapping.put("package1", ImmutableSet.of("database1", "database2"));
+        mAppSearchImpl.setSchema(
+                "package1",
+                "database2",
+                Collections.singletonList(new AppSearchSchema.Builder("schema").build()),
+                /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+                /*schemasPackageAccessible=*/ Collections.emptyMap(),
+                /*forceOverride=*/ false);
+        assertThat(mAppSearchImpl.getPackageToDatabases())
+                .containsExactlyEntriesIn(expectedMapping);
+
+        // Has both packages
+        expectedMapping.put("package2", ImmutableSet.of("database1"));
+        mAppSearchImpl.setSchema(
+                "package2",
+                "database1",
+                Collections.singletonList(new AppSearchSchema.Builder("schema").build()),
+                /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+                /*schemasPackageAccessible=*/ Collections.emptyMap(),
+                /*forceOverride=*/ false);
+        assertThat(mAppSearchImpl.getPackageToDatabases())
+                .containsExactlyEntriesIn(expectedMapping);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
index b98f025..205ff30 100644
--- a/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -23,6 +23,7 @@
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.when;
 
+import android.app.backup.BackupAgent;
 import android.app.backup.BackupManager.OperationType;
 import android.app.backup.IBackupManagerMonitor;
 import android.app.backup.IBackupObserver;
@@ -30,6 +31,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import com.android.internal.backup.IBackupTransport;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.runner.AndroidJUnit4;
@@ -56,6 +58,7 @@
     @Mock IBackupObserver mBackupObserver;
     @Mock PackageManager mPackageManager;
     @Mock TransportClient mTransportClient;
+    @Mock IBackupTransport mBackupTransport;
     @Mock BackupEligibilityRules mBackupEligibilityRules;
 
 
@@ -132,6 +135,33 @@
         assertThat(params.mBackupEligibilityRules).isEqualTo(mBackupEligibilityRules);
     }
 
+    @Test
+    public void testGetOperationTypeFromTransport_returnsBackupByDefault()
+            throws Exception {
+        when(mTransportClient.connectOrThrow(any())).thenReturn(mBackupTransport);
+        when(mBackupTransport.getTransportFlags()).thenReturn(0);
+
+        int operationType = mService.getOperationTypeFromTransport(mTransportClient);
+
+        assertThat(operationType).isEqualTo(OperationType.BACKUP);
+    }
+
+    @Test
+    public void testGetOperationTypeFromTransport_returnsMigrationForMigrationTransport()
+            throws Exception {
+        // This is a temporary flag to control the new behaviour until it's ready to be fully
+        // rolled out.
+        mService.shouldUseNewBackupEligibilityRules = true;
+
+        when(mTransportClient.connectOrThrow(any())).thenReturn(mBackupTransport);
+        when(mBackupTransport.getTransportFlags()).thenReturn(
+                BackupAgent.FLAG_DEVICE_TO_DEVICE_TRANSFER);
+
+        int operationType = mService.getOperationTypeFromTransport(mTransportClient);
+
+        assertThat(operationType).isEqualTo(OperationType.MIGRATION);
+    }
+
     private static PackageInfo getPackageInfo(String packageName) {
         PackageInfo packageInfo = new PackageInfo();
         packageInfo.applicationInfo = new ApplicationInfo();
@@ -141,6 +171,7 @@
 
     private static class TestBackupService extends UserBackupManagerService {
         boolean isEnabledStatePersisted = false;
+        boolean shouldUseNewBackupEligibilityRules = false;
 
         TestBackupService(Context context, PackageManager packageManager) {
             super(context, packageManager);
@@ -158,5 +189,10 @@
 
         @Override
         void updateStateOnBackupEnabled(boolean wasEnabled, boolean enable) {}
+
+        @Override
+        boolean shouldUseNewBackupEligibilityRules() {
+            return shouldUseNewBackupEligibilityRules;
+        }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index 8b0e948..b6b6932 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -602,12 +602,12 @@
                 .addEnableSinceSdkChangeWithId(2, 2L)
                 .build();
         compatConfig.forceNonDebuggableFinalForTest(true);
-        compatConfig.initOverrides(overridesFile);
+        compatConfig.initOverrides(overridesFile, new File(""));
         when(mPackageManager.getApplicationInfo(eq("foo.bar"), anyInt()))
                 .thenReturn(ApplicationInfoBuilder.create()
-                                .withPackageName("foo.bar")
-                                .debuggable()
-                                .build());
+                        .withPackageName("foo.bar")
+                        .debuggable()
+                        .build());
         when(mPackageManager.getApplicationInfo(eq("bar.baz"), anyInt()))
                 .thenThrow(new NameNotFoundException());
 
@@ -649,7 +649,7 @@
                 .addEnableSinceSdkChangeWithId(2, 2L)
                 .build();
         compatConfig.forceNonDebuggableFinalForTest(true);
-        compatConfig.initOverrides(overridesFile);
+        compatConfig.initOverrides(overridesFile, new File(""));
 
         compatConfig.addOverrides(new CompatibilityOverrideConfig(Collections.singletonMap(1L,
                 new PackageOverride.Builder()
@@ -673,11 +673,11 @@
     }
 
     @Test
-    public void testLoadOverridesRaw() throws Exception {
+    public void testInitOverridesRaw() throws Exception {
         File tempDir = createTempDir();
         File overridesFile = new File(tempDir, "overrides.xml");
         // Change 1 is enabled for foo.bar (validated)
-        // Change 2 is disabled for bar.baz (deferred)
+        // Change 2 is disabled for bar.baz (raw)
         String xmlData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
                 + "<overrides>\n"
                 + "    <change-overrides changeId=\"1\">\n"
@@ -709,7 +709,7 @@
                 .addEnableSinceSdkChangeWithId(2, 2L)
                 .build();
         compatConfig.forceNonDebuggableFinalForTest(true);
-        compatConfig.initOverrides(overridesFile);
+        compatConfig.initOverrides(overridesFile, new File(""));
         ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
                 .withPackageName("foo.bar")
                 .withVersionCode(100L)
@@ -728,7 +728,7 @@
     }
 
     @Test
-    public void testLoadOverridesDeferred() throws Exception {
+    public void testInitOverridesDeferred() throws Exception {
         File tempDir = createTempDir();
         File overridesFile = new File(tempDir, "overrides.xml");
         // Change 1 is enabled for foo.bar (validated)
@@ -754,7 +754,7 @@
                 .addEnableSinceSdkChangeWithId(2, 2L)
                 .build();
         compatConfig.forceNonDebuggableFinalForTest(true);
-        compatConfig.initOverrides(overridesFile);
+        compatConfig.initOverrides(overridesFile, new File(""));
         ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
                 .withPackageName("foo.bar")
                 .debuggable()
@@ -767,4 +767,115 @@
         assertThat(compatConfig.isChangeEnabled(1L, applicationInfo)).isTrue();
         assertThat(compatConfig.willChangeBeEnabled(2L, "bar.baz")).isFalse();
     }
+
+    @Test
+    public void testInitOverridesWithStaticFile() throws Exception {
+        File tempDir = createTempDir();
+        File dynamicOverridesFile = new File(tempDir, "dynamic_overrides.xml");
+        File staticOverridesFile = new File(tempDir, "static_overrides.xml");
+        // Change 1 is enabled for foo.bar (raw)
+        // Change 2 is disabled for bar.baz (raw)
+        String dynamicXmlData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+                + "<overrides>"
+                +    "<change-overrides changeId=\"1\">"
+                +        "<raw>"
+                + "            <raw-override-value packageName=\"foo.bar\" "
+                + "minVersionCode=\"-9223372036854775808\" "
+                + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+                + "            </raw-override-value>\n"
+                +        "</raw>"
+                +    "</change-overrides>"
+                +    "<change-overrides changeId=\"2\">"
+                +        "<raw>"
+                + "            <raw-override-value packageName=\"bar.baz\" "
+                + "minVersionCode=\"-9223372036854775808\" "
+                + "maxVersionCode=\"9223372036854775807\" enabled=\"false\">\n"
+                + "            </raw-override-value>\n"
+                +        "</raw>"
+                +    "</change-overrides>"
+                + "</overrides>";
+        writeToFile(tempDir, "dynamic_overrides.xml", dynamicXmlData);
+        // Change 2 is enabled for foo.bar and bar.baz (raw)
+        // Change 3 is enabled for bar.baz (raw)
+        String staticXmlData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+                + "<overrides>"
+                +    "<change-overrides changeId=\"2\">"
+                +        "<raw>"
+                + "            <raw-override-value packageName=\"foo.bar\" "
+                + "minVersionCode=\"-9223372036854775808\" "
+                + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+                + "            </raw-override-value>\n"
+                + "            <raw-override-value packageName=\"bar.baz\" "
+                + "minVersionCode=\"-9223372036854775808\" "
+                + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+                + "            </raw-override-value>\n"
+                +        "</raw>"
+                +    "</change-overrides>"
+                +    "<change-overrides changeId=\"3\">"
+                +        "<raw>"
+                + "            <raw-override-value packageName=\"bar.baz\" "
+                + "minVersionCode=\"-9223372036854775808\" "
+                + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+                + "            </raw-override-value>\n"
+                +        "</raw>"
+                +    "</change-overrides>"
+                + "</overrides>";
+        writeToFile(tempDir, "static_overrides.xml", staticXmlData);
+        CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+                .addDisabledChangeWithId(1L)
+                .addDisabledChangeWithId(2L)
+                .addDisabledChangeWithId(3L)
+                .build();
+        compatConfig.forceNonDebuggableFinalForTest(true);
+        // Adding an override that will be cleared after initOverrides is called.
+        compatConfig.addOverride(1L, "bar.baz", true);
+        compatConfig.initOverrides(dynamicOverridesFile, staticOverridesFile);
+        when(mPackageManager.getApplicationInfo(eq("foo.bar"), anyInt()))
+                .thenThrow(new NameNotFoundException());
+        when(mPackageManager.getApplicationInfo(eq("bar.baz"), anyInt()))
+                .thenThrow(new NameNotFoundException());
+
+        assertThat(compatConfig.willChangeBeEnabled(1L, "foo.bar")).isTrue();
+        assertThat(compatConfig.willChangeBeEnabled(2L, "foo.bar")).isTrue();
+        assertThat(compatConfig.willChangeBeEnabled(2L, "bar.baz")).isFalse();
+        assertThat(compatConfig.willChangeBeEnabled(3L, "bar.baz")).isTrue();
+        assertThat(readFile(dynamicOverridesFile))
+                .isEqualTo("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+                + "<overrides>\n"
+                + "    <change-overrides changeId=\"1\">\n"
+                + "        <validated>\n"
+                + "        </validated>\n"
+                + "        <raw>\n"
+                + "            <raw-override-value packageName=\"foo.bar\" "
+                + "minVersionCode=\"-9223372036854775808\" "
+                + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+                + "            </raw-override-value>\n"
+                + "        </raw>\n"
+                + "    </change-overrides>\n"
+                + "    <change-overrides changeId=\"2\">\n"
+                + "        <validated>\n"
+                + "        </validated>\n"
+                + "        <raw>\n"
+                + "            <raw-override-value packageName=\"foo.bar\" "
+                + "minVersionCode=\"-9223372036854775808\" "
+                + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+                + "            </raw-override-value>\n"
+                + "            <raw-override-value packageName=\"bar.baz\" "
+                + "minVersionCode=\"-9223372036854775808\" "
+                + "maxVersionCode=\"9223372036854775807\" enabled=\"false\">\n"
+                + "            </raw-override-value>\n"
+                + "        </raw>\n"
+                + "    </change-overrides>\n"
+                + "    <change-overrides changeId=\"3\">\n"
+                + "        <validated>\n"
+                + "        </validated>\n"
+                + "        <raw>\n"
+                + "            <raw-override-value packageName=\"bar.baz\" "
+                + "minVersionCode=\"-9223372036854775808\" "
+                + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+                + "            </raw-override-value>\n"
+                + "        </raw>\n"
+                + "    </change-overrides>\n"
+                + "</overrides>\n");
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
index 2cbc3f3..a694d5e 100644
--- a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
@@ -153,4 +153,25 @@
         assertEquals("Period not restored", periodic.periodMillis, oneoff.periodMillis);
         assertEquals("Flex not restored", periodic.flexMillis, oneoff.flexMillis);
     }
+
+    @SmallTest
+    public void testScheduleAsEjIsInExtras() {
+        Account account1 = new Account("account1", "type1");
+        Bundle b1 = new Bundle();
+        b1.putBoolean(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, true);
+
+        SyncOperation op1 = new SyncOperation(account1, 0, 1, "foo", 0,
+                SyncOperation.REASON_USER_START, "authority1", b1, false,
+                ContentResolver.SYNC_EXEMPTION_NONE);
+        assertTrue(op1.isScheduledAsExpeditedJob());
+
+        PersistableBundle pb = op1.toJobInfoExtras();
+        assertTrue("EJ extra not found in job extras",
+                ((PersistableBundle) pb.get("syncExtras"))
+                        .containsKey(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB));
+
+        SyncOperation op2 = SyncOperation.maybeCreateFromJobExtras(pb);
+        assertTrue("EJ extra not found in extras", op2.getClonedExtras()
+                .getBoolean(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB));
+    }
 }
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 6add8d1..87100a6 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -20,6 +20,8 @@
 import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE;
 import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
 import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
+import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
+import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
 import static android.app.admin.DevicePolicyManager.ID_TYPE_BASE_INFO;
 import static android.app.admin.DevicePolicyManager.ID_TYPE_IMEI;
 import static android.app.admin.DevicePolicyManager.ID_TYPE_MEID;
@@ -826,7 +828,7 @@
      * {@link DevicePolicyManager#forceRemoveActiveAdmin(ComponentName, int)}
      */
     @Test
-    public void testForceRemoveActiveAdmin() throws Exception {
+    public void testForceRemoveActiveAdmin_nonShellCaller() throws Exception {
         mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
 
         // Add admin.
@@ -840,8 +842,53 @@
         // Calling from a non-shell uid should fail with a SecurityException
         mContext.binder.callingUid = 123456;
         assertExpectException(SecurityException.class,
-                /* messageRegex =*/ "Non-shell user attempted to call",
+                /* messageRegex = */ null,
                 () -> dpms.forceRemoveActiveAdmin(admin1, CALLER_USER_HANDLE));
+    }
+
+    /**
+     * Test for:
+     * {@link DevicePolicyManager#forceRemoveActiveAdmin(ComponentName, int)}
+     */
+    @Test
+    public void testForceRemoveActiveAdmin_nonShellCallerWithPermission() throws Exception {
+        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+        // Add admin.
+        setupPackageInPackageManager(admin1.getPackageName(),
+                /* userId= */ CALLER_USER_HANDLE,
+                /* appId= */ 10138,
+                /* flags= */ ApplicationInfo.FLAG_TEST_ONLY);
+        dpm.setActiveAdmin(admin1, /* replace =*/ false);
+        assertThat(dpm.isAdminActive(admin1)).isTrue();
+
+        mContext.binder.callingUid = 123456;
+        mContext.callerPermissions.add(
+                android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        dpms.forceRemoveActiveAdmin(admin1, CALLER_USER_HANDLE);
+
+        mContext.callerPermissions.add(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+        // Verify
+        assertThat(dpm.isAdminActiveAsUser(admin1, CALLER_USER_HANDLE)).isFalse();
+        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
+                null, CALLER_USER_HANDLE);
+    }
+
+    /**
+     * Test for:
+     * {@link DevicePolicyManager#forceRemoveActiveAdmin(ComponentName, int)}
+     */
+    @Test
+    public void testForceRemoveActiveAdmin_ShellCaller() throws Exception {
+        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+        // Add admin.
+        setupPackageInPackageManager(admin1.getPackageName(),
+                /* userId= */ CALLER_USER_HANDLE,
+                /* appId= */ 10138,
+                /* flags= */ ApplicationInfo.FLAG_TEST_ONLY);
+        dpm.setActiveAdmin(admin1, /* replace =*/ false);
+        assertThat(dpm.isAdminActive(admin1)).isTrue();
 
         mContext.binder.callingUid = Process.SHELL_UID;
         dpms.forceRemoveActiveAdmin(admin1, CALLER_USER_HANDLE);
@@ -7028,6 +7075,71 @@
     }
 
     @Test
+    public void testSetDeviceOwnerType_throwsExceptionWhenCallerNotAuthorized() {
+        assertThrows(SecurityException.class,
+                () -> dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_DEFAULT));
+    }
+
+    @Test
+    public void testSetDeviceOwnerType_throwsExceptionWhenThereIsNoDeviceOwner() {
+        mContext.binder.clearCallingIdentity();
+        assertThrows(IllegalStateException.class,
+                () -> dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_DEFAULT));
+    }
+
+    @Test
+    public void testSetDeviceOwnerType_throwsExceptionWhenNotAsDeviceOwnerAdmin() throws Exception {
+        setDeviceOwner();
+
+        assertThrows(IllegalStateException.class,
+                () -> dpm.setDeviceOwnerType(admin2, DEVICE_OWNER_TYPE_FINANCED));
+    }
+
+    @Test
+    public void testSetDeviceOwnerType_asDeviceOwner_toFinancedDevice() throws Exception {
+        setDeviceOwner();
+
+        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);
+
+        int returnedDeviceOwnerType = dpm.getDeviceOwnerType(admin1);
+        assertThat(dpms.mOwners.hasDeviceOwner()).isTrue();
+        assertThat(returnedDeviceOwnerType).isEqualTo(DEVICE_OWNER_TYPE_FINANCED);
+
+        initializeDpms();
+
+        returnedDeviceOwnerType = dpm.getDeviceOwnerType(admin1);
+        assertThat(dpms.mOwners.hasDeviceOwner()).isTrue();
+        assertThat(returnedDeviceOwnerType).isEqualTo(DEVICE_OWNER_TYPE_FINANCED);
+    }
+
+    @Test
+    public void testSetDeviceOwnerType_asDeviceOwner_throwsExceptionWhenSetDeviceOwnerTypeAgain()
+            throws Exception {
+        setDeviceOwner();
+
+        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);
+
+        int returnedDeviceOwnerType = dpm.getDeviceOwnerType(admin1);
+        assertThat(dpms.mOwners.hasDeviceOwner()).isTrue();
+        assertThat(returnedDeviceOwnerType).isEqualTo(DEVICE_OWNER_TYPE_FINANCED);
+
+        assertThrows(IllegalStateException.class,
+                () -> dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_DEFAULT));
+    }
+
+    @Test
+    public void testGetDeviceOwnerType_throwsExceptionWhenThereIsNoDeviceOwner() {
+        assertThrows(IllegalStateException.class, () -> dpm.getDeviceOwnerType(admin1));
+    }
+
+    @Test
+    public void testGetDeviceOwnerType_throwsExceptionWhenNotAsDeviceOwnerAdmin() throws Exception {
+        setDeviceOwner();
+
+        assertThrows(IllegalStateException.class, () -> dpm.getDeviceOwnerType(admin2));
+    }
+
+    @Test
     public void testSetUsbDataSignalingEnabled_noDeviceOwnerOrPoOfOrgOwnedDevice() {
         assertThrows(SecurityException.class,
                 () -> dpm.setUsbDataSignalingEnabled(true));
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
index bfe183c..39ca925d 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
@@ -16,6 +16,9 @@
 
 package com.android.server.devicepolicy;
 
+import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
+import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.ComponentName;
@@ -35,7 +38,6 @@
  * <p>Run this test with:
  *
  * {@code atest FrameworksServicesTests:com.android.server.devicepolicy.OwnersTest}
- *
  */
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -67,6 +69,8 @@
 
             assertThat(owners.hasDeviceOwner()).isFalse();
             assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
+            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+                    DEVICE_OWNER_TYPE_DEFAULT);
             assertThat(owners.getSystemUpdatePolicy()).isNull();
             assertThat(owners.getProfileOwnerKeys()).isEmpty();
 
@@ -75,6 +79,12 @@
             assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isFalse();
             assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)).isFalse();
             assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse();
+
+            owners.setDeviceOwnerType(owners.getDeviceOwnerPackageName(),
+                    DEVICE_OWNER_TYPE_FINANCED);
+            // There is no device owner, so the default owner type should be returned.
+            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+                    DEVICE_OWNER_TYPE_DEFAULT);
         }
 
         // Then re-read and check.
@@ -84,6 +94,8 @@
 
             assertThat(owners.hasDeviceOwner()).isFalse();
             assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
+            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+                    DEVICE_OWNER_TYPE_DEFAULT);
             assertThat(owners.getSystemUpdatePolicy()).isNull();
             assertThat(owners.getProfileOwnerKeys()).isEmpty();
 
@@ -122,6 +134,8 @@
             assertThat(owners.getDeviceOwnerName()).isEqualTo(null);
             assertThat(owners.getDeviceOwnerPackageName()).isEqualTo("com.google.android.testdpc");
             assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM);
+            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+                    DEVICE_OWNER_TYPE_DEFAULT);
 
             assertThat(owners.getSystemUpdatePolicy()).isNull();
             assertThat(owners.getProfileOwnerKeys()).isEmpty();
@@ -142,6 +156,8 @@
             assertThat(owners.getDeviceOwnerName()).isEqualTo(null);
             assertThat(owners.getDeviceOwnerPackageName()).isEqualTo("com.google.android.testdpc");
             assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM);
+            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+                    DEVICE_OWNER_TYPE_DEFAULT);
 
             assertThat(owners.getSystemUpdatePolicy()).isNull();
             assertThat(owners.getProfileOwnerKeys()).isEmpty();
@@ -180,6 +196,8 @@
             assertThat(owners.hasDeviceOwner()).isFalse();
             assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
             assertThat(owners.getSystemUpdatePolicy()).isNull();
+            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+                    DEVICE_OWNER_TYPE_DEFAULT);
 
             assertThat(owners.getProfileOwnerKeys()).hasSize(2);
             assertThat(owners.getProfileOwnerComponent(10))
@@ -208,6 +226,8 @@
             assertThat(owners.hasDeviceOwner()).isFalse();
             assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
             assertThat(owners.getSystemUpdatePolicy()).isNull();
+            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+                    DEVICE_OWNER_TYPE_DEFAULT);
 
             assertThat(owners.getProfileOwnerKeys()).hasSize(2);
             assertThat(owners.getProfileOwnerComponent(10))
@@ -260,6 +280,8 @@
             assertThat(owners.getDeviceOwnerName()).isEqualTo(null);
             assertThat(owners.getDeviceOwnerPackageName()).isEqualTo("com.google.android.testdpc");
             assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM);
+            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+                    DEVICE_OWNER_TYPE_DEFAULT);
 
             assertThat(owners.getSystemUpdatePolicy()).isNotNull();
             assertThat(owners.getSystemUpdatePolicy().getPolicyType()).isEqualTo(5);
@@ -292,6 +314,8 @@
             assertThat(owners.getDeviceOwnerName()).isEqualTo(null);
             assertThat(owners.getDeviceOwnerPackageName()).isEqualTo("com.google.android.testdpc");
             assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_SYSTEM);
+            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+                    DEVICE_OWNER_TYPE_DEFAULT);
 
             assertThat(owners.getSystemUpdatePolicy()).isNotNull();
             assertThat(owners.getSystemUpdatePolicy().getPolicyType()).isEqualTo(5);
@@ -315,12 +339,21 @@
             assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse();
 
             owners.setDeviceOwnerUserRestrictionsMigrated();
+
+            owners.setDeviceOwnerType(owners.getDeviceOwnerPackageName(),
+                    DEVICE_OWNER_TYPE_FINANCED);
+            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+                    DEVICE_OWNER_TYPE_FINANCED);
         }
 
         {
             final OwnersTestable owners = new OwnersTestable(getServices());
             owners.load();
 
+            assertThat(owners.hasDeviceOwner()).isTrue();
+            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+                    DEVICE_OWNER_TYPE_FINANCED);
+
             assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse();
             assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isTrue();
             assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isTrue();
@@ -328,12 +361,22 @@
             assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)).isFalse();
 
             owners.setProfileOwnerUserRestrictionsMigrated(11);
+
+            owners.setDeviceOwnerType(owners.getDeviceOwnerPackageName(),
+                    DEVICE_OWNER_TYPE_DEFAULT);
+            // The previous device owner type should persist.
+            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+                    DEVICE_OWNER_TYPE_FINANCED);
         }
 
         {
             final OwnersTestable owners = new OwnersTestable(getServices());
             owners.load();
 
+            assertThat(owners.hasDeviceOwner()).isTrue();
+            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+                    DEVICE_OWNER_TYPE_FINANCED);
+
             assertThat(owners.getDeviceOwnerUserRestrictionsNeedsMigration()).isFalse();
             assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)).isTrue();
             assertThat(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)).isFalse();
@@ -369,6 +412,8 @@
 
             assertThat(owners.hasDeviceOwner()).isFalse();
             assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
+            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+                    DEVICE_OWNER_TYPE_DEFAULT);
 
 
             assertThat(owners.getSystemUpdatePolicy()).isNull();
@@ -388,6 +433,8 @@
 
             assertThat(owners.hasDeviceOwner()).isFalse();
             assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
+            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+                    DEVICE_OWNER_TYPE_DEFAULT);
 
 
             assertThat(owners.getSystemUpdatePolicy()).isNull();
@@ -425,6 +472,8 @@
 
             assertThat(owners.hasDeviceOwner()).isFalse();
             assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
+            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+                    DEVICE_OWNER_TYPE_DEFAULT);
             assertThat(owners.getProfileOwnerKeys()).isEmpty();
 
             assertThat(owners.getSystemUpdatePolicy()).isNotNull();
@@ -444,6 +493,8 @@
 
             assertThat(owners.hasDeviceOwner()).isFalse();
             assertThat(owners.getDeviceOwnerUserId()).isEqualTo(UserHandle.USER_NULL);
+            assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+                    DEVICE_OWNER_TYPE_DEFAULT);
             assertThat(owners.getProfileOwnerKeys()).isEmpty();
 
             assertThat(owners.getSystemUpdatePolicy()).isNotNull();
@@ -472,9 +523,16 @@
         assertThat(owners.getLegacyConfigFile().exists()).isFalse();
 
         assertThat(owners.getDeviceOwnerFile().exists()).isTrue();
+        assertThat(owners.getDeviceOwnerType(owners.getDeviceOwnerPackageName())).isEqualTo(
+                DEVICE_OWNER_TYPE_DEFAULT);
         assertThat(owners.getProfileOwnerFile(10).exists()).isTrue();
         assertThat(owners.getProfileOwnerFile(11).exists()).isTrue();
 
+        String previousDeviceOwnerPackageName = owners.getDeviceOwnerPackageName();
+        owners.setDeviceOwnerType(previousDeviceOwnerPackageName, DEVICE_OWNER_TYPE_FINANCED);
+        assertThat(owners.getDeviceOwnerType(previousDeviceOwnerPackageName)).isEqualTo(
+                DEVICE_OWNER_TYPE_FINANCED);
+
         // Then clear all information and save.
         owners.clearDeviceOwner();
         owners.clearSystemUpdatePolicy();
@@ -491,5 +549,8 @@
         assertThat(owners.getDeviceOwnerFile().exists()).isFalse();
         assertThat(owners.getProfileOwnerFile(10).exists()).isFalse();
         assertThat(owners.getProfileOwnerFile(11).exists()).isFalse();
+
+        assertThat(owners.getDeviceOwnerType(previousDeviceOwnerPackageName)).isEqualTo(
+                DEVICE_OWNER_TYPE_DEFAULT);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
index a078a77..a97ea26 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
@@ -21,8 +21,10 @@
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertThrows;
 
+import android.hardware.devicestate.DeviceStateInfo;
 import android.hardware.devicestate.DeviceStateRequest;
 import android.hardware.devicestate.IDeviceStateManagerCallback;
 import android.os.Binder;
@@ -33,10 +35,13 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import junit.framework.Assert;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Optional;
 
@@ -70,14 +75,14 @@
     public void baseStateChanged() {
         assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 DEFAULT_DEVICE_STATE.getIdentifier());
 
         mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
         assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState().get(), OTHER_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), OTHER_DEVICE_STATE);
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 OTHER_DEVICE_STATE.getIdentifier());
     }
@@ -89,21 +94,21 @@
         mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
         assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getPendingState().get(), OTHER_DEVICE_STATE);
-        assertEquals(mService.getBaseState().get(), OTHER_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), OTHER_DEVICE_STATE);
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 OTHER_DEVICE_STATE.getIdentifier());
 
         mProvider.setState(DEFAULT_DEVICE_STATE.getIdentifier());
         assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getPendingState().get(), OTHER_DEVICE_STATE);
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 OTHER_DEVICE_STATE.getIdentifier());
 
         mPolicy.resumeConfigure();
         assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 DEFAULT_DEVICE_STATE.getIdentifier());
     }
@@ -116,7 +121,7 @@
 
         assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 DEFAULT_DEVICE_STATE.getIdentifier());
     }
@@ -129,16 +134,19 @@
 
         assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 DEFAULT_DEVICE_STATE.getIdentifier());
     }
 
     @Test
-    public void supportedStatesChanged() {
+    public void supportedStatesChanged() throws RemoteException {
+        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        mService.getBinderService().registerCallback(callback);
+
         assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
 
         mProvider.notifySupportedDeviceStates(new DeviceState[]{ DEFAULT_DEVICE_STATE });
 
@@ -146,27 +154,44 @@
         // supported.
         assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+
+        assertArrayEquals(callback.getLastNotifiedInfo().supportedStates,
+                new int[] { DEFAULT_DEVICE_STATE.getIdentifier() });
     }
 
     @Test
-    public void supportedStatesChanged_unsupportedBaseState() {
+    public void supportedStatesChanged_statesRemainSame() throws RemoteException {
+        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        mService.getBinderService().registerCallback(callback);
+
         assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
 
-        mProvider.notifySupportedDeviceStates(new DeviceState[]{ OTHER_DEVICE_STATE });
+        mProvider.notifySupportedDeviceStates(new DeviceState[]{ DEFAULT_DEVICE_STATE,
+                OTHER_DEVICE_STATE });
 
-        // The current requested state is cleared because it is no longer supported.
+        // The current committed and requests states do not change because the current state remains
+        // supported.
         assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState(), Optional.empty());
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
 
-        mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
+        // The callback wasn't notified about a change in supported states as the states have not
+        // changed.
+        assertNull(callback.getLastNotifiedInfo());
+    }
 
-        assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
-        assertEquals(mService.getPendingState(), Optional.empty());
-        assertEquals(mService.getBaseState().get(), OTHER_DEVICE_STATE);
+    @Test
+    public void getDeviceStateInfo() throws RemoteException {
+        DeviceStateInfo info = mService.getBinderService().getDeviceStateInfo();
+        assertNotNull(info);
+        assertArrayEquals(info.supportedStates,
+                new int[] { DEFAULT_DEVICE_STATE.getIdentifier(),
+                        OTHER_DEVICE_STATE.getIdentifier() });
+        assertEquals(info.baseState, DEFAULT_DEVICE_STATE.getIdentifier());
+        assertEquals(info.currentState, DEFAULT_DEVICE_STATE.getIdentifier());
     }
 
     @Test
@@ -175,41 +200,33 @@
         mService.getBinderService().registerCallback(callback);
 
         mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
-        assertNotNull(callback.getLastNotifiedValue());
-        assertEquals(callback.getLastNotifiedValue().intValue(),
+        assertEquals(callback.getLastNotifiedInfo().baseState,
+                OTHER_DEVICE_STATE.getIdentifier());
+        assertEquals(callback.getLastNotifiedInfo().currentState,
                 OTHER_DEVICE_STATE.getIdentifier());
 
         mProvider.setState(DEFAULT_DEVICE_STATE.getIdentifier());
-        assertEquals(callback.getLastNotifiedValue().intValue(),
+        assertEquals(callback.getLastNotifiedInfo().baseState,
+                DEFAULT_DEVICE_STATE.getIdentifier());
+        assertEquals(callback.getLastNotifiedInfo().currentState,
                 DEFAULT_DEVICE_STATE.getIdentifier());
 
         mPolicy.blockConfigure();
         mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
         // The callback should not have been notified of the state change as the policy is still
         // pending callback.
-        assertEquals(callback.getLastNotifiedValue().intValue(),
+        assertEquals(callback.getLastNotifiedInfo().baseState,
+                DEFAULT_DEVICE_STATE.getIdentifier());
+        assertEquals(callback.getLastNotifiedInfo().currentState,
                 DEFAULT_DEVICE_STATE.getIdentifier());
 
         mPolicy.resumeConfigure();
         // Now that the policy is finished processing the callback should be notified of the state
         // change.
-        assertEquals(callback.getLastNotifiedValue().intValue(),
+        assertEquals(callback.getLastNotifiedInfo().baseState,
                 OTHER_DEVICE_STATE.getIdentifier());
-    }
-
-    @Test
-    public void registerCallback_emitsInitialValue() throws RemoteException {
-        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
-        mService.getBinderService().registerCallback(callback);
-        assertNotNull(callback.getLastNotifiedValue());
-        assertEquals(callback.getLastNotifiedValue().intValue(),
-                DEFAULT_DEVICE_STATE.getIdentifier());
-    }
-
-    @Test
-    public void getSupportedDeviceStates() throws RemoteException {
-        final int[] expectedStates = new int[] { 0, 1 };
-        assertEquals(mService.getBinderService().getSupportedDeviceStates(), expectedStates);
+        assertEquals(callback.getLastNotifiedInfo().currentState,
+                OTHER_DEVICE_STATE.getIdentifier());
     }
 
     @Test
@@ -228,11 +245,16 @@
                 TestDeviceStateManagerCallback.STATUS_ACTIVE);
         // Committed state changes as there is a requested override.
         assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE);
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 OTHER_DEVICE_STATE.getIdentifier());
 
+        assertNotNull(callback.getLastNotifiedInfo());
+        assertEquals(callback.getLastNotifiedInfo().baseState,
+                DEFAULT_DEVICE_STATE.getIdentifier());
+        assertEquals(callback.getLastNotifiedInfo().currentState,
+                OTHER_DEVICE_STATE.getIdentifier());
 
         mService.getBinderService().cancelRequest(token);
 
@@ -240,10 +262,96 @@
                 TestDeviceStateManagerCallback.STATUS_CANCELED);
         // Committed state is set back to the requested state once the override is cleared.
         assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
         assertFalse(mService.getOverrideState().isPresent());
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 DEFAULT_DEVICE_STATE.getIdentifier());
+
+        assertEquals(callback.getLastNotifiedInfo().baseState,
+                DEFAULT_DEVICE_STATE.getIdentifier());
+        assertEquals(callback.getLastNotifiedInfo().currentState,
+                DEFAULT_DEVICE_STATE.getIdentifier());
+    }
+
+    @Test
+    public void requestState_pendingStateAtRequest() throws RemoteException {
+        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        mService.getBinderService().registerCallback(callback);
+
+        mPolicy.blockConfigure();
+
+        final IBinder firstRequestToken = new Binder();
+        final IBinder secondRequestToken = new Binder();
+        assertEquals(callback.getLastNotifiedStatus(firstRequestToken),
+                TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+        assertEquals(callback.getLastNotifiedStatus(secondRequestToken),
+                TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+
+        mService.getBinderService().requestState(firstRequestToken,
+                OTHER_DEVICE_STATE.getIdentifier(), 0 /* flags */);
+
+        assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getPendingState().get(), OTHER_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
+                OTHER_DEVICE_STATE.getIdentifier());
+
+        mService.getBinderService().requestState(secondRequestToken,
+                DEFAULT_DEVICE_STATE.getIdentifier(), 0 /* flags */);
+
+        mPolicy.resumeConfigureOnce();
+
+        // First request status is now suspended as there is another pending request.
+        assertEquals(callback.getLastNotifiedStatus(firstRequestToken),
+                TestDeviceStateManagerCallback.STATUS_SUSPENDED);
+        // Second request status still unknown because the service is still awaiting policy
+        // callback.
+        assertEquals(callback.getLastNotifiedStatus(secondRequestToken),
+                TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+
+        assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
+        assertEquals(mService.getPendingState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
+                DEFAULT_DEVICE_STATE.getIdentifier());
+
+        mPolicy.resumeConfigure();
+
+        assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getPendingState(), Optional.empty());
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
+                DEFAULT_DEVICE_STATE.getIdentifier());
+
+        // Now cancel the second request to make the first request active.
+        mService.getBinderService().cancelRequest(secondRequestToken);
+
+        assertEquals(callback.getLastNotifiedStatus(firstRequestToken),
+                TestDeviceStateManagerCallback.STATUS_ACTIVE);
+        assertEquals(callback.getLastNotifiedStatus(secondRequestToken),
+                TestDeviceStateManagerCallback.STATUS_CANCELED);
+
+        assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
+        assertEquals(mService.getPendingState(), Optional.empty());
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+        assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
+                OTHER_DEVICE_STATE.getIdentifier());
+    }
+
+    @Test
+    public void requestState_sameAsBaseState() throws RemoteException {
+        TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+        mService.getBinderService().registerCallback(callback);
+
+        final IBinder token = new Binder();
+        assertEquals(callback.getLastNotifiedStatus(token),
+                TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+
+        mService.getBinderService().requestState(token, DEFAULT_DEVICE_STATE.getIdentifier(),
+                0 /* flags */);
+
+        assertEquals(callback.getLastNotifiedStatus(token),
+                TestDeviceStateManagerCallback.STATUS_ACTIVE);
     }
 
     @Test
@@ -263,7 +371,7 @@
 
         // Committed state changes as there is a requested override.
         assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE);
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 OTHER_DEVICE_STATE.getIdentifier());
@@ -275,7 +383,7 @@
                 TestDeviceStateManagerCallback.STATUS_CANCELED);
         // Committed state is set back to the requested state once the override is cleared.
         assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
-        assertEquals(mService.getBaseState().get(), OTHER_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), OTHER_DEVICE_STATE);
         assertFalse(mService.getOverrideState().isPresent());
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 OTHER_DEVICE_STATE.getIdentifier());
@@ -297,7 +405,7 @@
                 TestDeviceStateManagerCallback.STATUS_ACTIVE);
         // Committed state changes as there is a requested override.
         assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
         assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE);
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 OTHER_DEVICE_STATE.getIdentifier());
@@ -310,7 +418,7 @@
         // Committed state is set back to the requested state as the override state is no longer
         // supported.
         assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
-        assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+        assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
         assertFalse(mService.getOverrideState().isPresent());
         assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
                 DEFAULT_DEVICE_STATE.getIdentifier());
@@ -348,6 +456,10 @@
         });
     }
 
+    private static void assertArrayEquals(int[] expected, int[] actual) {
+        Assert.assertTrue(Arrays.equals(expected, actual));
+    }
+
     private static final class TestDeviceStatePolicy implements DeviceStatePolicy {
         private final DeviceStateProvider mProvider;
         private int mLastDeviceStateRequestedToConfigure = INVALID_DEVICE_STATE;
@@ -376,6 +488,14 @@
             }
         }
 
+        public void resumeConfigureOnce() {
+            if (mPendingConfigureCompleteRunnable != null) {
+                Runnable onComplete = mPendingConfigureCompleteRunnable;
+                mPendingConfigureCompleteRunnable = null;
+                onComplete.run();
+            }
+        }
+
         public int getMostRecentRequestedStateToConfigure() {
             return mLastDeviceStateRequestedToConfigure;
         }
@@ -429,12 +549,14 @@
         public static final int STATUS_SUSPENDED = 2;
         public static final int STATUS_CANCELED = 3;
 
-        private Integer mLastNotifiedValue;
+        @Nullable
+        private DeviceStateInfo mLastNotifiedInfo;
+        private boolean mNotifiedOfChangeInSupportedStates;
         private final HashMap<IBinder, Integer> mLastNotifiedStatus = new HashMap<>();
 
         @Override
-        public void onDeviceStateChanged(int deviceState) {
-            mLastNotifiedValue = deviceState;
+        public void onDeviceStateInfoChanged(DeviceStateInfo info) {
+            mLastNotifiedInfo = info;
         }
 
         @Override
@@ -453,8 +575,8 @@
         }
 
         @Nullable
-        Integer getLastNotifiedValue() {
-            return mLastNotifiedValue;
+        DeviceStateInfo getLastNotifiedInfo() {
+            return mLastNotifiedInfo;
         }
 
         int getLastNotifiedStatus(IBinder requestToken) {
diff --git a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
index 23a4c2f..54825ee 100644
--- a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -64,7 +64,6 @@
     @Mock HysteresisLevels mAmbientBrightnessThresholds;
     @Mock HysteresisLevels mScreenBrightnessThresholds;
     @Mock Handler mNoOpHandler;
-    @Mock DisplayDeviceConfig mDisplayDeviceConfig;
     @Mock DisplayDevice mDisplayDevice;
 
     private static final int LIGHT_SENSOR_WARMUP_TIME = 0;
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
index f0b4f1b..285806b 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
@@ -88,7 +88,9 @@
     };
 
     private static final float[] DISPLAY_RANGE_NITS = { 2.685f, 478.5f };
-    private static final int[] BACKLIGHT_RANGE = { 1, 255 };
+    private static final float[] DISPLAY_LEVELS_RANGE_NITS = { 13.25f, 478.5f };
+    private static final float[] BACKLIGHT_RANGE_ZERO_TO_ONE = { 0.0f, 1.0f };
+    private static final float[] DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT = { 0.03149606299f, 1.0f };
 
     private static final float[] EMPTY_FLOAT_ARRAY = new float[0];
     private static final int[] EMPTY_INT_ARRAY = new int[0];
@@ -114,25 +116,28 @@
     };
     private static final Spline GAMMA_CORRECTION_SPLINE = Spline.createSpline(
             new float[] { 0.0f, 100.0f, 1000.0f, 2500.0f, 4000.0f, 4900.0f, 5000.0f },
-            new float[] { 0.035f, 0.035f, 0.221f, 0.523f, 0.797f, 0.980f, 1.0f });
+            new float[] { 0.0475f, 0.0475f, 0.2225f, 0.5140f, 0.8056f, 0.9805f, 1.0f });
 
     @Test
     public void testSimpleStrategyMappingAtControlPoints() {
         Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT);
-        BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res);
+        DisplayDeviceConfig ddc = createDdc();
+        BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc);
         assertNotNull("BrightnessMappingStrategy should not be null", simple);
         for (int i = 0; i < LUX_LEVELS.length; i++) {
-            final float expectedLevel =
-                    (float) DISPLAY_LEVELS_BACKLIGHT[i] / PowerManager.BRIGHTNESS_ON;
+            final float expectedLevel = MathUtils.map(PowerManager.BRIGHTNESS_OFF + 1,
+                    PowerManager.BRIGHTNESS_ON, PowerManager.BRIGHTNESS_MIN,
+                    PowerManager.BRIGHTNESS_MAX, DISPLAY_LEVELS_BACKLIGHT[i]);
             assertEquals(expectedLevel,
-                    simple.getBrightness(LUX_LEVELS[i]), 0.01f /*tolerance*/);
+                    simple.getBrightness(LUX_LEVELS[i]), 0.0001f /*tolerance*/);
         }
     }
 
     @Test
     public void testSimpleStrategyMappingBetweenControlPoints() {
         Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT);
-        BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res);
+        DisplayDeviceConfig ddc = createDdc();
+        BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc);
         assertNotNull("BrightnessMappingStrategy should not be null", simple);
         for (int i = 1; i < LUX_LEVELS.length; i++) {
             final float lux = (LUX_LEVELS[i - 1] + LUX_LEVELS[i]) / 2;
@@ -146,66 +151,71 @@
     @Test
     public void testSimpleStrategyIgnoresNewConfiguration() {
         Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT);
-        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
+        DisplayDeviceConfig ddc = createDdc();
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
 
-        final int N = LUX_LEVELS.length;
         final float[] lux = { 0f, 1f };
         final float[] nits = { 0, PowerManager.BRIGHTNESS_ON };
 
         BrightnessConfiguration config = new BrightnessConfiguration.Builder(lux, nits)
                 .build();
         strategy.setBrightnessConfiguration(config);
-        assertNotEquals(1.0f, strategy.getBrightness(1f), 0.01 /*tolerance*/);
+        assertNotEquals(1.0f, strategy.getBrightness(1f), 0.0001f /*tolerance*/);
     }
 
     @Test
     public void testSimpleStrategyIgnoresNullConfiguration() {
         Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT);
-        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
+        DisplayDeviceConfig ddc = createDdc();
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
 
         strategy.setBrightnessConfiguration(null);
         final int N = DISPLAY_LEVELS_BACKLIGHT.length;
         final float expectedBrightness =
                 (float) DISPLAY_LEVELS_BACKLIGHT[N - 1] / PowerManager.BRIGHTNESS_ON;
         assertEquals(expectedBrightness,
-                strategy.getBrightness(LUX_LEVELS[N - 1]), 0.01 /*tolerance*/);
+                strategy.getBrightness(LUX_LEVELS[N - 1]), 0.0001f /*tolerance*/);
     }
 
     @Test
     public void testPhysicalStrategyMappingAtControlPoints() {
-        Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS,
-                DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
-        BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res);
+        Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS);
+        DisplayDeviceConfig ddc = createDdc();
+        BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc);
         assertNotNull("BrightnessMappingStrategy should not be null", physical);
         for (int i = 0; i < LUX_LEVELS.length; i++) {
-            final float expectedLevel = DISPLAY_LEVELS_NITS[i] / DISPLAY_RANGE_NITS[1];
+            final float expectedLevel = MathUtils.map(DISPLAY_RANGE_NITS[0], DISPLAY_RANGE_NITS[1],
+                    DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT[0],
+                    DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT[1],
+                    DISPLAY_LEVELS_NITS[i]);
             assertEquals(expectedLevel,
-                    physical.getBrightness(LUX_LEVELS[i]), 0.01f /*tolerance*/);
+                    physical.getBrightness(LUX_LEVELS[i]),
+                    0.0001f /*tolerance*/);
         }
     }
 
     @Test
     public void testPhysicalStrategyMappingBetweenControlPoints() {
-        Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS,
-                DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
-        BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res);
+        Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS);
+        DisplayDeviceConfig ddc = createDdc(DISPLAY_RANGE_NITS, BACKLIGHT_RANGE_ZERO_TO_ONE);
+        BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc);
         assertNotNull("BrightnessMappingStrategy should not be null", physical);
-        Spline backlightToBrightness =
-                Spline.createSpline(toFloatArray(BACKLIGHT_RANGE), DISPLAY_RANGE_NITS);
+        Spline brightnessToNits =
+                Spline.createSpline(BACKLIGHT_RANGE_ZERO_TO_ONE, DISPLAY_RANGE_NITS);
         for (int i = 1; i < LUX_LEVELS.length; i++) {
-            final float lux = (LUX_LEVELS[i - 1] + LUX_LEVELS[i]) / 2;
-            final float backlight = physical.getBrightness(lux) * PowerManager.BRIGHTNESS_ON;
-            final float nits = backlightToBrightness.interpolate(backlight);
-            assertTrue("Desired brightness should be between adjacent control points.",
+            final float lux = (LUX_LEVELS[i - 1] + LUX_LEVELS[i]) / 2.0f;
+            final float brightness = physical.getBrightness(lux);
+            final float nits = brightnessToNits.interpolate(brightness);
+            assertTrue("Desired brightness should be between adjacent control points: " + nits,
                     nits > DISPLAY_LEVELS_NITS[i - 1] && nits < DISPLAY_LEVELS_NITS[i]);
         }
     }
 
     @Test
     public void testPhysicalStrategyUsesNewConfigurations() {
-        Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS,
-                DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
-        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
+        Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS);
+        DisplayDeviceConfig ddc = createDdc();
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
 
         final float[] lux = { 0f, 1f };
         final float[] nits = {
@@ -216,46 +226,53 @@
         BrightnessConfiguration config = new BrightnessConfiguration.Builder(lux, nits)
                 .build();
         strategy.setBrightnessConfiguration(config);
-        assertEquals(1.0f, strategy.getBrightness(1f), 0.01 /*tolerance*/);
+        assertEquals(1.0f, strategy.getBrightness(1f), 0.0001f /*tolerance*/);
 
         // Check that null returns us to the default configuration.
         strategy.setBrightnessConfiguration(null);
         final int N = DISPLAY_LEVELS_NITS.length;
         final float expectedBrightness = DISPLAY_LEVELS_NITS[N - 1] / DISPLAY_RANGE_NITS[1];
         assertEquals(expectedBrightness,
-                strategy.getBrightness(LUX_LEVELS[N - 1]), 0.01f /*tolerance*/);
+                strategy.getBrightness(LUX_LEVELS[N - 1]), 0.0001f /*tolerance*/);
     }
 
     @Test
     public void testPhysicalStrategyRecalculateSplines() {
-        Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS,
-                BACKLIGHT_RANGE);
-        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
+        Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS);
+        DisplayDeviceConfig ddc = createDdc(DISPLAY_RANGE_NITS);
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
         float[] adjustedNits50p = new float[DISPLAY_RANGE_NITS.length];
         for (int i = 0; i < DISPLAY_RANGE_NITS.length; i++) {
             adjustedNits50p[i] = DISPLAY_RANGE_NITS[i] * 0.5f;
         }
 
         // Default is unadjusted
-        assertEquals(2.685f, strategy.convertToNits(BACKLIGHT_RANGE[0]), 0.01f /* tolerance */);
-        assertEquals(478.5f, strategy.convertToNits(BACKLIGHT_RANGE[1]), 0.01f /* tolerance */);
+        assertEquals(DISPLAY_RANGE_NITS[0], strategy.convertToNits(BACKLIGHT_RANGE_ZERO_TO_ONE[0]),
+                0.0001f /* tolerance */);
+        assertEquals(DISPLAY_RANGE_NITS[1], strategy.convertToNits(BACKLIGHT_RANGE_ZERO_TO_ONE[1]),
+                0.0001f /* tolerance */);
 
         // When adjustment is turned on, adjustment array is used
         strategy.recalculateSplines(true, adjustedNits50p);
-        assertEquals(1.3425f, strategy.convertToNits(BACKLIGHT_RANGE[0]), 0.01f /* tolerance */);
-        assertEquals(239.25f, strategy.convertToNits(BACKLIGHT_RANGE[1]), 0.01f /* tolerance */);
+        assertEquals(DISPLAY_RANGE_NITS[0] / 2,
+                strategy.convertToNits(BACKLIGHT_RANGE_ZERO_TO_ONE[0]), 0.0001f /* tolerance */);
+        assertEquals(DISPLAY_RANGE_NITS[1] / 2,
+                strategy.convertToNits(BACKLIGHT_RANGE_ZERO_TO_ONE[1]), 0.0001f /* tolerance */);
 
         // When adjustment is turned off, adjustment array is ignored
         strategy.recalculateSplines(false, adjustedNits50p);
-        assertEquals(2.685f, strategy.convertToNits(BACKLIGHT_RANGE[0]), 0.01f /* tolerance */);
-        assertEquals(478.5f, strategy.convertToNits(BACKLIGHT_RANGE[1]), 0.01f /* tolerance */);
+        assertEquals(DISPLAY_RANGE_NITS[0], strategy.convertToNits(BACKLIGHT_RANGE_ZERO_TO_ONE[0]),
+                0.0001f /* tolerance */);
+        assertEquals(DISPLAY_RANGE_NITS[1], strategy.convertToNits(BACKLIGHT_RANGE_ZERO_TO_ONE[1]),
+                0.0001f /* tolerance */);
     }
 
     @Test
     public void testDefaultStrategyIsPhysical() {
         Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT,
-                DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
-        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
+                DISPLAY_LEVELS_NITS);
+        DisplayDeviceConfig ddc = createDdc();
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
         assertTrue(strategy instanceof BrightnessMappingStrategy.PhysicalMappingStrategy);
     }
 
@@ -266,15 +283,15 @@
         int tmp = lux[idx];
         lux[idx] = lux[idx+1];
         lux[idx+1] = tmp;
-        Resources res = createResources(lux, DISPLAY_LEVELS_NITS,
-                DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
-        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
+        Resources res = createResources(lux, DISPLAY_LEVELS_NITS);
+        DisplayDeviceConfig ddc = createDdc();
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
         assertNull(strategy);
 
         // And make sure we get the same result even if it's monotone but not increasing.
         lux[idx] = lux[idx+1];
-        res = createResources(lux, DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
-        strategy = BrightnessMappingStrategy.create(res);
+        res = createResources(lux, DISPLAY_LEVELS_NITS);
+        strategy = BrightnessMappingStrategy.create(res, ddc);
         assertNull(strategy);
     }
 
@@ -285,13 +302,13 @@
         // Make sure it's strictly increasing so that the only failure is the differing array
         // lengths
         lux[lux.length - 1] = lux[lux.length - 2] + 1;
-        Resources res = createResources(lux, DISPLAY_LEVELS_NITS,
-                DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
-        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
+        Resources res = createResources(lux, DISPLAY_LEVELS_NITS);
+        DisplayDeviceConfig ddc = createDdc();
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
         assertNull(strategy);
 
         res = createResources(lux, DISPLAY_LEVELS_BACKLIGHT);
-        strategy = BrightnessMappingStrategy.create(res);
+        strategy = BrightnessMappingStrategy.create(res, ddc);
         assertNull(strategy);
 
         // Extra backlight level
@@ -299,43 +316,45 @@
                 DISPLAY_LEVELS_BACKLIGHT, DISPLAY_LEVELS_BACKLIGHT.length+1);
         backlight[backlight.length - 1] = backlight[backlight.length - 2] + 1;
         res = createResources(LUX_LEVELS, backlight);
-        strategy = BrightnessMappingStrategy.create(res);
+        strategy = BrightnessMappingStrategy.create(res, ddc);
         assertNull(strategy);
 
         // Extra nits level
         final float[] nits = Arrays.copyOf(DISPLAY_RANGE_NITS, DISPLAY_LEVELS_NITS.length+1);
         nits[nits.length - 1] = nits[nits.length - 2] + 1;
-        res = createResources(LUX_LEVELS, nits, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
-        strategy = BrightnessMappingStrategy.create(res);
+        res = createResources(LUX_LEVELS, nits);
+        strategy = BrightnessMappingStrategy.create(res, ddc);
         assertNull(strategy);
     }
 
     @Test
     public void testPhysicalStrategyRequiresNitsMapping() {
         Resources res = createResources(LUX_LEVELS, EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/,
-                DISPLAY_LEVELS_NITS, EMPTY_FLOAT_ARRAY /*nitsRange*/, BACKLIGHT_RANGE);
-        BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res);
+                DISPLAY_LEVELS_NITS);
+        DisplayDeviceConfig ddc = createDdc(EMPTY_FLOAT_ARRAY /*nitsRange*/);
+        BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc);
         assertNull(physical);
 
         res = createResources(LUX_LEVELS, EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/,
-                DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS, EMPTY_INT_ARRAY /*backlightRange*/);
-        physical = BrightnessMappingStrategy.create(res);
+                DISPLAY_LEVELS_NITS);
+        physical = BrightnessMappingStrategy.create(res, ddc);
         assertNull(physical);
 
         res = createResources(LUX_LEVELS, EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/,
-                DISPLAY_LEVELS_NITS, EMPTY_FLOAT_ARRAY /*nitsRange*/,
-                EMPTY_INT_ARRAY /*backlightRange*/);
-        physical = BrightnessMappingStrategy.create(res);
+                DISPLAY_LEVELS_NITS);
+        physical = BrightnessMappingStrategy.create(res, ddc);
         assertNull(physical);
     }
 
     @Test
     public void testStrategiesAdaptToUserDataPoint() {
-        Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS,
-                DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
-        assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res));
+        Resources res = createResources(LUX_LEVELS, EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/,
+                DISPLAY_LEVELS_NITS);
+        DisplayDeviceConfig ddc = createDdc(DISPLAY_RANGE_NITS, BACKLIGHT_RANGE_ZERO_TO_ONE);
+        assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res, ddc));
+        ddc = createDdc(DISPLAY_RANGE_NITS, BACKLIGHT_RANGE_ZERO_TO_ONE);
         res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT);
-        assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res));
+        assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res, ddc));
     }
 
     private static void assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy strategy) {
@@ -351,7 +370,7 @@
 
         // Then make sure that all control points after the middle lux level are also set to max...
         for (int i = idx; i < LUX_LEVELS.length; i++) {
-            assertEquals(strategy.getBrightness(LUX_LEVELS[idx]), 1.0, 0.01 /*tolerance*/);
+            assertEquals(strategy.getBrightness(LUX_LEVELS[idx]), 1.0, 0.0001f /*tolerance*/);
         }
 
         // ...and that all control points before the middle lux level are strictly less than the
@@ -369,12 +388,12 @@
         strategy.clearUserDataPoints();
         for (int i = 0; i < LUX_LEVELS.length; i++) {
             assertEquals(initialBrightnessLevels[i], strategy.getBrightness(LUX_LEVELS[i]),
-                    0.01 /*tolerance*/);
+                    0.0001f /*tolerance*/);
         }
 
         // Now set the middle of the lux range to something just above the minimum.
         float minBrightness = strategy.getBrightness(LUX_LEVELS[0]);
-        strategy.addUserDataPoint(LUX_LEVELS[idx], minBrightness + 0.01f);
+        strategy.addUserDataPoint(LUX_LEVELS[idx], minBrightness + 0.0001f);
 
         // Then make sure the curve is still monotonic.
         prevBrightness = 0f;
@@ -389,31 +408,21 @@
         // be true assuming that there are more than two lux levels in the curve since we picked a
         // brightness just barely above the minimum for the middle of the curve.
         minBrightness = (float) MathUtils.pow(minBrightness, MAXIMUM_GAMMA); // Gamma correction.
-        assertEquals(minBrightness, strategy.getBrightness(LUX_LEVELS[0]), 0.01 /*tolerance*/);
-    }
-
-    private static float[] toFloatArray(int[] vals) {
-        float[] newVals = new float[vals.length];
-        for (int i = 0; i < vals.length; i++) {
-            newVals[i] = (float) vals[i];
-        }
-        return newVals;
+        assertEquals(minBrightness, strategy.getBrightness(LUX_LEVELS[0]), 0.0001f /*tolerance*/);
     }
 
     private Resources createResources(int[] luxLevels, int[] brightnessLevelsBacklight) {
         return createResources(luxLevels, brightnessLevelsBacklight,
-                EMPTY_FLOAT_ARRAY /*brightnessLevelsNits*/, EMPTY_FLOAT_ARRAY /*nitsRange*/,
-                EMPTY_INT_ARRAY /*backlightRange*/);
+                EMPTY_FLOAT_ARRAY /*brightnessLevelsNits*/);
     }
 
-    private Resources createResources(int[] luxLevels, float[] brightnessLevelsNits,
-            float[] nitsRange, int[] backlightRange) {
+    private Resources createResources(int[] luxLevels, float[] brightnessLevelsNits) {
         return createResources(luxLevels, EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/,
-                brightnessLevelsNits, nitsRange, backlightRange);
+                brightnessLevelsNits);
     }
 
     private Resources createResources(int[] luxLevels, int[] brightnessLevelsBacklight,
-            float[] brightnessLevelsNits, float[] nitsRange, int[] backlightRange) {
+            float[] brightnessLevelsNits) {
         Resources mockResources = mock(Resources.class);
         // For historical reasons, the lux levels resource implicitly defines the first point as 0,
         // so we need to chop it off of the array the mock resource object returns.
@@ -430,15 +439,6 @@
                 com.android.internal.R.array.config_autoBrightnessDisplayValuesNits))
                 .thenReturn(mockBrightnessLevelNits);
 
-        TypedArray mockNitsRange = createFloatTypedArray(nitsRange);
-        when(mockResources.obtainTypedArray(
-                com.android.internal.R.array.config_screenBrightnessNits))
-                .thenReturn(mockNitsRange);
-
-        when(mockResources.getIntArray(
-                com.android.internal.R.array.config_screenBrightnessBacklight))
-                .thenReturn(backlightRange);
-
         when(mockResources.getInteger(
                 com.android.internal.R.integer.config_screenBrightnessSettingMinimum))
                 .thenReturn(1);
@@ -451,6 +451,21 @@
         return mockResources;
     }
 
+    private DisplayDeviceConfig createDdc() {
+        return createDdc(DISPLAY_RANGE_NITS);
+    }
+
+    private DisplayDeviceConfig createDdc(float[] nitsArray) {
+        return createDdc(nitsArray, DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT);
+    }
+
+    private DisplayDeviceConfig createDdc(float[] nitsArray, float[] backlightArray) {
+        DisplayDeviceConfig mockDdc = mock(DisplayDeviceConfig.class);
+        when(mockDdc.getNits()).thenReturn(nitsArray);
+        when(mockDdc.getBrightness()).thenReturn(backlightArray);
+        return mockDdc;
+    }
+
     private TypedArray createFloatTypedArray(float[] vals) {
         TypedArray mockArray = mock(TypedArray.class);
         when(mockArray.length()).thenAnswer(invocation -> {
@@ -488,21 +503,22 @@
         final float y1 = GAMMA_CORRECTION_SPLINE.interpolate(x1);
         final float y2 = GAMMA_CORRECTION_SPLINE.interpolate(x2);
         final float y3 = GAMMA_CORRECTION_SPLINE.interpolate(x3);
-        Resources resources = createResources(GAMMA_CORRECTION_LUX, GAMMA_CORRECTION_NITS,
-                DISPLAY_LEVELS_NITS, DISPLAY_LEVELS_BACKLIGHT);
-        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources);
+
+        Resources resources = createResources(GAMMA_CORRECTION_LUX, GAMMA_CORRECTION_NITS);
+        DisplayDeviceConfig ddc = createDdc();
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc);
         // Let's start with a validity check:
-        assertEquals(y1, strategy.getBrightness(x1), 0.01f /* tolerance */);
-        assertEquals(y2, strategy.getBrightness(x2), 0.01f /* tolerance */);
-        assertEquals(y3, strategy.getBrightness(x3), 0.01f /* tolerance */);
+        assertEquals(y1, strategy.getBrightness(x1), 0.0001f /* tolerance */);
+        assertEquals(y2, strategy.getBrightness(x2), 0.0001f /* tolerance */);
+        assertEquals(y3, strategy.getBrightness(x3), 0.0001f /* tolerance */);
         // OK, let's roll:
         float gamma = 0.5f;
         strategy.addUserDataPoint(x2, (float) MathUtils.pow(y2, gamma));
-        assertEquals(MathUtils.pow(y1, gamma), strategy.getBrightness(x1), 0.01f /* tolerance */);
-        assertEquals(MathUtils.pow(y2, gamma), strategy.getBrightness(x2), 0.01f /* tolerance */);
-        assertEquals(MathUtils.pow(y3, gamma), strategy.getBrightness(x3), 0.01f /* tolerance */);
-        // The adjustment should be +0.63 (manual calculation).
-        assertEquals(+0.63f, strategy.getAutoBrightnessAdjustment(), 0.01f /* tolerance */);
+        assertEquals(MathUtils.pow(y1, gamma), strategy.getBrightness(x1), 0.0001f /* tolerance */);
+        assertEquals(MathUtils.pow(y2, gamma), strategy.getBrightness(x2), 0.0001f /* tolerance */);
+        assertEquals(MathUtils.pow(y3, gamma), strategy.getBrightness(x3), 0.0001f /* tolerance */);
+        // The adjustment should be +0.6308 (manual calculation).
+        assertEquals(+0.6308f, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
     }
 
     @Test
@@ -516,39 +532,39 @@
         final float y1 = GAMMA_CORRECTION_SPLINE.interpolate(x1);
         final float y2 = GAMMA_CORRECTION_SPLINE.interpolate(x2);
         final float y3 = GAMMA_CORRECTION_SPLINE.interpolate(x3);
-        Resources resources = createResources(GAMMA_CORRECTION_LUX, GAMMA_CORRECTION_NITS,
-                DISPLAY_LEVELS_NITS, DISPLAY_LEVELS_BACKLIGHT);
-        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources);
+        Resources resources = createResources(GAMMA_CORRECTION_LUX, GAMMA_CORRECTION_NITS);
+        DisplayDeviceConfig ddc = createDdc();
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc);
         // Validity check:
-        assertEquals(y1, strategy.getBrightness(x1), 0.01f /* tolerance */);
-        assertEquals(y2, strategy.getBrightness(x2), 0.01f /* tolerance */);
-        assertEquals(y3, strategy.getBrightness(x3), 0.01f /* tolerance */);
+        assertEquals(y1, strategy.getBrightness(x1), 0.0001f /* tolerance */);
+        assertEquals(y2, strategy.getBrightness(x2), 0.0001f /* tolerance */);
+        assertEquals(y3, strategy.getBrightness(x3), 0.0001f /* tolerance */);
         // Let's roll:
         float gamma = 0.25f;
         final float minGamma = 1.0f / MAXIMUM_GAMMA;
         strategy.addUserDataPoint(x2, (float) MathUtils.pow(y2, gamma));
-        assertEquals(MathUtils.pow(y1, minGamma), strategy.getBrightness(x1),
-                0.01f /* tolerance */);
-        assertEquals(MathUtils.pow(y2, gamma),    strategy.getBrightness(x2),
-                0.01f /* tolerance */);
-        assertEquals(MathUtils.pow(y3, minGamma), strategy.getBrightness(x3),
-                0.01f /* tolerance */);
+        assertEquals(MathUtils.pow(y1, minGamma),
+                strategy.getBrightness(x1), 0.0001f /* tolerance */);
+        assertEquals(MathUtils.pow(y2, gamma),
+                strategy.getBrightness(x2), 0.0001f /* tolerance */);
+        assertEquals(MathUtils.pow(y3, minGamma),
+                strategy.getBrightness(x3), 0.0001f /* tolerance */);
         // The adjustment should be +1.0 (maximum adjustment).
-        assertEquals(+1.0f, strategy.getAutoBrightnessAdjustment(), 0.01f /* tolerance */);
+        assertEquals(+1.0f, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
     }
 
     @Test
     public void testGammaCorrectionExtremeChangeAtCenter() {
         // Extreme changes (e.g. setting brightness to 0.0 or 1.0) can't be gamma corrected, so we
         // just make sure the adjustment reflects the change.
-        Resources resources = createResources(GAMMA_CORRECTION_LUX, GAMMA_CORRECTION_NITS,
-                DISPLAY_LEVELS_NITS, DISPLAY_LEVELS_BACKLIGHT);
-        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources);
-        assertEquals(0.0f, strategy.getAutoBrightnessAdjustment(), 0.01f /* tolerance */);
+        Resources resources = createResources(GAMMA_CORRECTION_LUX, GAMMA_CORRECTION_NITS);
+        DisplayDeviceConfig ddc = createDdc();
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc);
+        assertEquals(0.0f, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
         strategy.addUserDataPoint(2500, 1.0f);
-        assertEquals(+1.0f, strategy.getAutoBrightnessAdjustment(), 0.01f /* tolerance */);
+        assertEquals(+1.0f, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
         strategy.addUserDataPoint(2500, 0.0f);
-        assertEquals(-1.0f, strategy.getAutoBrightnessAdjustment(), 0.01f /* tolerance */);
+        assertEquals(-1.0f, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
     }
 
     @Test
@@ -562,28 +578,28 @@
         final float y0 = GAMMA_CORRECTION_SPLINE.interpolate(x0);
         final float y2 = GAMMA_CORRECTION_SPLINE.interpolate(x2);
         final float y4 = GAMMA_CORRECTION_SPLINE.interpolate(x4);
-        Resources resources = createResources(GAMMA_CORRECTION_LUX, GAMMA_CORRECTION_NITS,
-                DISPLAY_LEVELS_NITS, DISPLAY_LEVELS_BACKLIGHT);
-        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources);
+        Resources resources = createResources(GAMMA_CORRECTION_LUX, GAMMA_CORRECTION_NITS);
+        DisplayDeviceConfig ddc = createDdc();
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc);
         // Validity, as per tradition:
-        assertEquals(y0, strategy.getBrightness(x0), 0.01f /* tolerance */);
-        assertEquals(y2, strategy.getBrightness(x2), 0.01f /* tolerance */);
-        assertEquals(y4, strategy.getBrightness(x4), 0.01f /* tolerance */);
+        assertEquals(y0, strategy.getBrightness(x0), 0.0001f /* tolerance */);
+        assertEquals(y2, strategy.getBrightness(x2), 0.0001f /* tolerance */);
+        assertEquals(y4, strategy.getBrightness(x4), 0.0001f /* tolerance */);
         // Rollin':
         float adjustment = 0.3f;
         float gamma = (float) MathUtils.pow(MAXIMUM_GAMMA, -adjustment);
         strategy.addUserDataPoint(x0, y0 + adjustment);
-        assertEquals(y0 + adjustment, strategy.getBrightness(x0), 0.01f /* tolerance */);
-        assertEquals(MathUtils.pow(y2, gamma), strategy.getBrightness(x2), 0.01f /* tolerance */);
-        assertEquals(MathUtils.pow(y4, gamma), strategy.getBrightness(x4), 0.01f /* tolerance */);
-        assertEquals(adjustment, strategy.getAutoBrightnessAdjustment(), 0.01f /* tolerance */);
+        assertEquals(y0 + adjustment, strategy.getBrightness(x0), 0.0001f /* tolerance */);
+        assertEquals(MathUtils.pow(y2, gamma), strategy.getBrightness(x2), 0.0001f /* tolerance */);
+        assertEquals(MathUtils.pow(y4, gamma), strategy.getBrightness(x4), 0.0001f /* tolerance */);
+        assertEquals(adjustment, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
         // Similarly, if we set a user data point at (x4, 1.0), the adjustment should be 1 - y4.
         adjustment = 1.0f - y4;
         gamma = (float) MathUtils.pow(MAXIMUM_GAMMA, -adjustment);
         strategy.addUserDataPoint(x4, 1.0f);
-        assertEquals(MathUtils.pow(y0, gamma), strategy.getBrightness(x0), 0.01f /* tolerance */);
-        assertEquals(MathUtils.pow(y2, gamma), strategy.getBrightness(x2), 0.01f /* tolerance */);
-        assertEquals(1.0f, strategy.getBrightness(x4), 0.01f /* tolerance */);
-        assertEquals(adjustment, strategy.getAutoBrightnessAdjustment(), 0.01f /* tolerance */);
+        assertEquals(MathUtils.pow(y0, gamma), strategy.getBrightness(x0), 0.0001f /* tolerance */);
+        assertEquals(MathUtils.pow(y2, gamma), strategy.getBrightness(x2), 0.0001f /* tolerance */);
+        assertEquals(1.0f, strategy.getBrightness(x4), 0.0001f /* tolerance */);
+        assertEquals(adjustment, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index 81b2381..15ada89 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -88,6 +88,7 @@
     private static final String TAG = "DisplayModeDirectorTest";
     private static final boolean DEBUG = false;
     private static final float FLOAT_TOLERANCE = 0.01f;
+    private static final int DISPLAY_ID = 0;
 
     private Context mContext;
     private FakesInjector mInjector;
@@ -107,19 +108,29 @@
 
     private DisplayModeDirector createDirectorFromRefreshRateArray(
             float[] refreshRates, int baseModeId) {
+        return createDirectorFromRefreshRateArray(refreshRates, baseModeId, refreshRates[0]);
+    }
+
+    private DisplayModeDirector createDirectorFromRefreshRateArray(
+            float[] refreshRates, int baseModeId, float defaultRefreshRate) {
         DisplayModeDirector director =
                 new DisplayModeDirector(mContext, mHandler, mInjector);
-        int displayId = 0;
         Display.Mode[] modes = new Display.Mode[refreshRates.length];
+        Display.Mode defaultMode = null;
         for (int i = 0; i < refreshRates.length; i++) {
             modes[i] = new Display.Mode(
                     /*modeId=*/baseModeId + i, /*width=*/1000, /*height=*/1000, refreshRates[i]);
+            if (refreshRates[i] == defaultRefreshRate) {
+                defaultMode = modes[i];
+            }
         }
+        assertThat(defaultMode).isNotNull();
+
         SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<>();
-        supportedModesByDisplay.put(displayId, modes);
+        supportedModesByDisplay.put(DISPLAY_ID, modes);
         director.injectSupportedModesByDisplay(supportedModesByDisplay);
         SparseArray<Display.Mode> defaultModesByDisplay = new SparseArray<>();
-        defaultModesByDisplay.put(displayId, modes[0]);
+        defaultModesByDisplay.put(DISPLAY_ID, defaultMode);
         director.injectDefaultModeByDisplay(defaultModesByDisplay);
         return director;
     }
@@ -130,16 +141,15 @@
         for (int i = 0; i < numRefreshRates; i++) {
             refreshRates[i] = minFps + i;
         }
-        return createDirectorFromRefreshRateArray(refreshRates, /*baseModeId=*/minFps);
+        return createDirectorFromRefreshRateArray(refreshRates, /*baseModeId=*/minFps,
+                /*defaultRefreshRate=*/minFps);
     }
 
     @Test
     public void testDisplayModeVoting() {
-        int displayId = 0;
-
         // With no votes present, DisplayModeDirector should allow any refresh rate.
         DesiredDisplayModeSpecs modeSpecs =
-                createDirectorFromFpsRange(60, 90).getDesiredDisplayModeSpecs(displayId);
+                createDirectorFromFpsRange(60, 90).getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(modeSpecs.baseModeId).isEqualTo(60);
         assertThat(modeSpecs.primaryRefreshRateRange.min).isEqualTo(0f);
         assertThat(modeSpecs.primaryRefreshRateRange.max).isEqualTo(Float.POSITIVE_INFINITY);
@@ -156,12 +166,12 @@
             assertTrue(2 * numPriorities < maxFps - minFps + 1);
             SparseArray<Vote> votes = new SparseArray<>();
             SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
-            votesByDisplay.put(displayId, votes);
+            votesByDisplay.put(DISPLAY_ID, votes);
             for (int i = 0; i < numPriorities; i++) {
                 int priority = Vote.MIN_PRIORITY + i;
                 votes.put(priority, Vote.forRefreshRates(minFps + i, maxFps - i));
                 director.injectVotesByDisplay(votesByDisplay);
-                modeSpecs = director.getDesiredDisplayModeSpecs(displayId);
+                modeSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
                 assertThat(modeSpecs.baseModeId).isEqualTo(minFps + i);
                 assertThat(modeSpecs.primaryRefreshRateRange.min)
                         .isEqualTo((float) (minFps + i));
@@ -177,11 +187,11 @@
             DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
             SparseArray<Vote> votes = new SparseArray<>();
             SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
-            votesByDisplay.put(displayId, votes);
+            votesByDisplay.put(DISPLAY_ID, votes);
             votes.put(Vote.MAX_PRIORITY, Vote.forRefreshRates(65, 85));
             votes.put(Vote.MIN_PRIORITY, Vote.forRefreshRates(70, 80));
             director.injectVotesByDisplay(votesByDisplay);
-            modeSpecs = director.getDesiredDisplayModeSpecs(displayId);
+            modeSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
             assertThat(modeSpecs.baseModeId).isEqualTo(70);
             assertThat(modeSpecs.primaryRefreshRateRange.min).isEqualTo(70f);
             assertThat(modeSpecs.primaryRefreshRateRange.max).isEqualTo(80f);
@@ -190,18 +200,17 @@
 
     @Test
     public void testVotingWithFloatingPointErrors() {
-        int displayId = 0;
         DisplayModeDirector director = createDirectorFromFpsRange(50, 90);
         SparseArray<Vote> votes = new SparseArray<>();
         SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
-        votesByDisplay.put(displayId, votes);
+        votesByDisplay.put(DISPLAY_ID, votes);
         float error = FLOAT_TOLERANCE / 4;
         votes.put(Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE, Vote.forRefreshRates(0, 60));
         votes.put(Vote.PRIORITY_APP_REQUEST_SIZE, Vote.forRefreshRates(60 + error, 60 + error));
         votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE,
                 Vote.forRefreshRates(60 - error, 60 - error));
         director.injectVotesByDisplay(votesByDisplay);
-        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
 
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
@@ -213,15 +222,14 @@
         assertTrue(PRIORITY_FLICKER < Vote.PRIORITY_APP_REQUEST_REFRESH_RATE);
         assertTrue(PRIORITY_FLICKER < Vote.PRIORITY_APP_REQUEST_SIZE);
 
-        int displayId = 0;
         DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
         SparseArray<Vote> votes = new SparseArray<>();
         SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
-        votesByDisplay.put(displayId, votes);
+        votesByDisplay.put(DISPLAY_ID, votes);
         votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 90));
         votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60));
         director.injectVotesByDisplay(votesByDisplay);
-        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
 
@@ -229,7 +237,7 @@
         votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 90));
         votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(90, 90));
         director.injectVotesByDisplay(votesByDisplay);
-        desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90);
 
@@ -237,7 +245,7 @@
         votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(90, 90));
         votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60));
         director.injectVotesByDisplay(votesByDisplay);
-        desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90);
 
@@ -245,7 +253,7 @@
         votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 60));
         votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(90, 90));
         director.injectVotesByDisplay(votesByDisplay);
-        desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
     }
@@ -261,14 +269,13 @@
         assertTrue(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE
                 >= Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
 
-        int displayId = 0;
         DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
         SparseArray<Vote> votes = new SparseArray<>();
         SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
-        votesByDisplay.put(displayId, votes);
+        votesByDisplay.put(DISPLAY_ID, votes);
         votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60));
         director.injectVotesByDisplay(votesByDisplay);
-        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.appRequestRefreshRateRange.min).isAtMost(60f);
@@ -277,7 +284,7 @@
         votes.put(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE,
                 Vote.forRefreshRates(90, Float.POSITIVE_INFINITY));
         director.injectVotesByDisplay(votesByDisplay);
-        desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isAtLeast(90f);
         assertThat(desiredSpecs.appRequestRefreshRateRange.min).isAtMost(60f);
@@ -285,7 +292,7 @@
 
         votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(75, 75));
         director.injectVotesByDisplay(votesByDisplay);
-        desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(75);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(75);
         assertThat(desiredSpecs.appRequestRefreshRateRange.min)
@@ -355,11 +362,10 @@
 
     @Test
     public void testVotingWithAlwaysRespectAppRequest() {
-        final int displayId = 0;
         DisplayModeDirector director = createDirectorFromFpsRange(50, 90);
         SparseArray<Vote> votes = new SparseArray<>();
         SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
-        votesByDisplay.put(displayId, votes);
+        votesByDisplay.put(DISPLAY_ID, votes);
         votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(0, 60));
         votes.put(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE, Vote.forRefreshRates(60, 90));
         votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(90, 90));
@@ -369,7 +375,7 @@
 
         director.injectVotesByDisplay(votesByDisplay);
         assertThat(director.shouldAlwaysRespectAppRequestedMode()).isFalse();
-        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
 
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
@@ -377,7 +383,7 @@
 
         director.setShouldAlwaysRespectAppRequestedMode(true);
         assertThat(director.shouldAlwaysRespectAppRequestedMode()).isTrue();
-        desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90);
         assertThat(desiredSpecs.baseModeId).isEqualTo(90);
@@ -385,7 +391,7 @@
         director.setShouldAlwaysRespectAppRequestedMode(false);
         assertThat(director.shouldAlwaysRespectAppRequestedMode()).isFalse();
 
-        desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.baseModeId).isEqualTo(60);
@@ -393,11 +399,10 @@
 
     @Test
     public void testVotingWithSwitchingTypeNone() {
-        final int displayId = 0;
         DisplayModeDirector director = createDirectorFromFpsRange(0, 90);
         SparseArray<Vote> votes = new SparseArray<>();
         SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
-        votesByDisplay.put(displayId, votes);
+        votesByDisplay.put(DISPLAY_ID, votes);
         votes.put(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE, Vote.forRefreshRates(30, 90));
         votes.put(Vote.PRIORITY_LOW_POWER_MODE, Vote.forRefreshRates(0, 60));
 
@@ -405,7 +410,7 @@
         director.injectVotesByDisplay(votesByDisplay);
         assertThat(director.getModeSwitchingType())
                 .isNotEqualTo(DisplayManager.SWITCHING_TYPE_NONE);
-        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
 
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(30);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
@@ -417,7 +422,7 @@
         assertThat(director.getModeSwitchingType())
                 .isEqualTo(DisplayManager.SWITCHING_TYPE_NONE);
 
-        desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(30);
         assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(30);
         assertThat(desiredSpecs.appRequestRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(30);
@@ -427,29 +432,38 @@
 
     @Test
     public void testVotingWithSwitchingTypeWithinGroups() {
-        final int displayId = 0;
         DisplayModeDirector director = createDirectorFromFpsRange(0, 90);
 
         director.setModeSwitchingType(DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS);
         assertThat(director.getModeSwitchingType())
                 .isEqualTo(DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS);
-        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.allowGroupSwitching).isFalse();
     }
 
     @Test
     public void testVotingWithSwitchingTypeWithinAndAcrossGroups() {
-        final int displayId = 0;
         DisplayModeDirector director = createDirectorFromFpsRange(0, 90);
 
         director.setModeSwitchingType(DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS);
         assertThat(director.getModeSwitchingType())
                 .isEqualTo(DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS);
-        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.allowGroupSwitching).isTrue();
     }
 
     @Test
+    public void testDefaultDisplayModeIsSelectedIfAvailable() {
+        final float[] refreshRates = new float[]{24f, 25f, 30f, 60f, 90f};
+        final int defaultModeId = 3;
+        DisplayModeDirector director = createDirectorFromRefreshRateArray(
+                refreshRates, /*baseModeId=*/0, refreshRates[defaultModeId]);
+
+        DesiredDisplayModeSpecs specs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+        assertThat(specs.baseModeId).isEqualTo(defaultModeId);
+    }
+
+    @Test
     public void testBrightnessObserverGetsUpdatedRefreshRatesForZone() {
         DisplayModeDirector director =
                 createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, /* baseModeId= */ 0);
diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
new file mode 100644
index 0000000..bcd853c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -0,0 +1,327 @@
+/*
+ * 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.display;
+
+import static com.android.server.display.DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED;
+import static com.android.server.display.DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED;
+import static com.android.server.display.DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED;
+import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_ADDED;
+import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REMOVED;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.verify;
+
+import android.app.PropertyInvalidatedCache;
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Process;
+import android.platform.test.annotations.Presubmit;
+import android.view.Display;
+import android.view.DisplayAddress;
+import android.view.DisplayInfo;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class LogicalDisplayMapperTest {
+    private static int sUniqueTestDisplayId = 0;
+
+    private DisplayDeviceRepository mDisplayDeviceRepo;
+    private LogicalDisplayMapper mLogicalDisplayMapper;
+    private Context mContext;
+
+    @Mock LogicalDisplayMapper.Listener mListenerMock;
+
+    @Captor ArgumentCaptor<LogicalDisplay> mDisplayCaptor;
+
+    @Before
+    public void setUp() {
+        // Share classloader to allow package private access.
+        System.setProperty("dexmaker.share_classloader", "true");
+        MockitoAnnotations.initMocks(this);
+
+        mContext = InstrumentationRegistry.getContext();
+        mDisplayDeviceRepo = new DisplayDeviceRepository(
+                new DisplayManagerService.SyncRoot(),
+                new PersistentDataStore(new PersistentDataStore.Injector() {
+                    @Override
+                    public InputStream openRead() {
+                        return null;
+                    }
+
+                    @Override
+                    public OutputStream startWrite() {
+                        return null;
+                    }
+
+                    @Override
+                    public void finishWrite(OutputStream os, boolean success) {}
+                }));
+
+        // Disable binder caches in this process.
+        PropertyInvalidatedCache.disableForTestMode();
+
+        mLogicalDisplayMapper = new LogicalDisplayMapper(mDisplayDeviceRepo, mListenerMock);
+    }
+
+
+    /////////////////
+    // Test Methods
+    /////////////////
+
+    @Test
+    public void testDisplayDeviceAddAndRemove_Internal() {
+        DisplayDevice device = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
+                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY);
+
+        // add
+        LogicalDisplay displayAdded = add(device);
+        assertEquals(info(displayAdded).address, info(device).address);
+        assertEquals(Display.DEFAULT_DISPLAY, id(displayAdded));
+
+        // remove
+        mDisplayDeviceRepo.onDisplayDeviceEvent(device, DISPLAY_DEVICE_EVENT_REMOVED);
+        verify(mListenerMock).onLogicalDisplayEventLocked(
+                mDisplayCaptor.capture(), eq(LOGICAL_DISPLAY_EVENT_REMOVED));
+        LogicalDisplay displayRemoved = mDisplayCaptor.getValue();
+        assertEquals(Display.DEFAULT_DISPLAY, id(displayRemoved));
+        assertEquals(displayAdded, displayRemoved);
+    }
+
+    @Test
+    public void testDisplayDeviceAddAndRemove_NonInternalTypes() {
+        testDisplayDeviceAddAndRemove_NonInternal(Display.TYPE_EXTERNAL);
+        testDisplayDeviceAddAndRemove_NonInternal(Display.TYPE_WIFI);
+        testDisplayDeviceAddAndRemove_NonInternal(Display.TYPE_OVERLAY);
+        testDisplayDeviceAddAndRemove_NonInternal(Display.TYPE_VIRTUAL);
+        testDisplayDeviceAddAndRemove_NonInternal(Display.TYPE_UNKNOWN);
+
+        // Call the internal test again, just to verify that adding non-internal displays
+        // doesn't affect the ability for an internal display to become the default display.
+        testDisplayDeviceAddAndRemove_Internal();
+    }
+
+    @Test
+    public void testDisplayDeviceAdd_TwoInternalOneDefault() {
+        DisplayDevice device1 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, 0);
+        DisplayDevice device2 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
+                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY);
+
+        LogicalDisplay display1 = add(device1);
+        assertEquals(info(display1).address, info(device1).address);
+        assertNotEquals(Display.DEFAULT_DISPLAY, id(display1));
+
+        LogicalDisplay display2 = add(device2);
+        assertEquals(info(display2).address, info(device2).address);
+        assertEquals(Display.DEFAULT_DISPLAY, id(display2));
+    }
+
+    @Test
+    public void testDisplayDeviceAdd_TwoInternalBothDefault() {
+        DisplayDevice device1 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
+                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY);
+        DisplayDevice device2 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
+                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY);
+
+        LogicalDisplay display1 = add(device1);
+        assertEquals(info(display1).address, info(device1).address);
+        assertEquals(Display.DEFAULT_DISPLAY, id(display1));
+
+        LogicalDisplay display2 = add(device2);
+        assertEquals(info(display2).address, info(device2).address);
+        // Despite the flags, we can only have one default display
+        assertNotEquals(Display.DEFAULT_DISPLAY, id(display2));
+    }
+
+    @Test
+    public void testGetDisplayIdsLocked() {
+        add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
+                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
+        add(createDisplayDevice(Display.TYPE_EXTERNAL, 600, 800, 0));
+        add(createDisplayDevice(Display.TYPE_VIRTUAL, 600, 800, 0));
+
+        int [] ids = mLogicalDisplayMapper.getDisplayIdsLocked(Process.SYSTEM_UID);
+        assertEquals(3, ids.length);
+        Arrays.sort(ids);
+        assertEquals(Display.DEFAULT_DISPLAY, ids[0]);
+    }
+
+    @Test
+    public void testSingleDisplayGroup() {
+        LogicalDisplay display1 = add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
+                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
+        LogicalDisplay display2 = add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, 0));
+        LogicalDisplay display3 = add(createDisplayDevice(Display.TYPE_VIRTUAL, 600, 800, 0));
+
+        assertEquals(Display.DEFAULT_DISPLAY_GROUP,
+                mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display1)));
+        assertEquals(Display.DEFAULT_DISPLAY_GROUP,
+                mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display2)));
+        assertEquals(Display.DEFAULT_DISPLAY_GROUP,
+                mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display3)));
+    }
+
+    @Test
+    public void testMultipleDisplayGroups() {
+        LogicalDisplay display1 = add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
+                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
+        LogicalDisplay display2 = add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, 0));
+
+
+        TestDisplayDevice device3 = createDisplayDevice(Display.TYPE_VIRTUAL, 600, 800,
+                DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP);
+        LogicalDisplay display3 = add(device3);
+
+        assertEquals(Display.DEFAULT_DISPLAY_GROUP,
+                mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display1)));
+        assertEquals(Display.DEFAULT_DISPLAY_GROUP,
+                mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display2)));
+        assertNotEquals(Display.DEFAULT_DISPLAY_GROUP,
+                mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display3)));
+
+        // Now switch it back to the default group by removing the flag and issuing an update
+        DisplayDeviceInfo info = device3.getSourceInfo();
+        info.flags = info.flags & ~DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP;
+        mDisplayDeviceRepo.onDisplayDeviceEvent(device3, DISPLAY_DEVICE_EVENT_CHANGED);
+
+        // Verify the new group is correct.
+        assertEquals(Display.DEFAULT_DISPLAY_GROUP,
+                mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display3)));
+    }
+
+
+    /////////////////
+    // Helper Methods
+    /////////////////
+
+    private TestDisplayDevice createDisplayDevice(int type, int width, int height, int flags) {
+        return createDisplayDevice(new DisplayAddressImpl(), type, width, height, flags);
+    }
+
+    private TestDisplayDevice createDisplayDevice(
+            DisplayAddress address, int type, int width, int height, int flags) {
+        TestDisplayDevice device = new TestDisplayDevice();
+        DisplayDeviceInfo displayDeviceInfo = device.getSourceInfo();
+        displayDeviceInfo.type = type;
+        displayDeviceInfo.width = width;
+        displayDeviceInfo.height = height;
+        displayDeviceInfo.flags = flags;
+        displayDeviceInfo.address = new DisplayAddressImpl();
+        return device;
+    }
+
+    private DisplayDeviceInfo info(DisplayDevice device) {
+        return device.getDisplayDeviceInfoLocked();
+    }
+
+    private DisplayInfo info(LogicalDisplay display) {
+        return display.getDisplayInfoLocked();
+    }
+
+    private int id(LogicalDisplay display) {
+        return display.getDisplayIdLocked();
+    }
+
+    private LogicalDisplay add(DisplayDevice device) {
+        mDisplayDeviceRepo.onDisplayDeviceEvent(device, DISPLAY_DEVICE_EVENT_ADDED);
+        ArgumentCaptor<LogicalDisplay> displayCaptor =
+                ArgumentCaptor.forClass(LogicalDisplay.class);
+        verify(mListenerMock).onLogicalDisplayEventLocked(
+                displayCaptor.capture(), eq(LOGICAL_DISPLAY_EVENT_ADDED));
+        clearInvocations(mListenerMock);
+        return displayCaptor.getValue();
+    }
+
+    private void testDisplayDeviceAddAndRemove_NonInternal(int type) {
+        DisplayDevice device = createDisplayDevice(type, 600, 800, 0);
+
+        // add
+        LogicalDisplay displayAdded = add(device);
+        assertEquals(info(displayAdded).address, info(device).address);
+        assertNotEquals(Display.DEFAULT_DISPLAY, id(displayAdded));
+
+        // remove
+        mDisplayDeviceRepo.onDisplayDeviceEvent(device, DISPLAY_DEVICE_EVENT_REMOVED);
+        verify(mListenerMock).onLogicalDisplayEventLocked(
+                mDisplayCaptor.capture(), eq(LOGICAL_DISPLAY_EVENT_REMOVED));
+        LogicalDisplay displayRemoved = mDisplayCaptor.getValue();
+        assertNotEquals(Display.DEFAULT_DISPLAY, id(displayRemoved));
+    }
+
+    /**
+     * Create a custom {@link DisplayAddress} to ensure we're not relying on any specific
+     * display-address implementation in our code. Intentionally uses default object (reference)
+     * equality rules.
+     */
+    class DisplayAddressImpl extends DisplayAddress {
+        @Override
+        public void writeToParcel(Parcel out, int flags) { }
+    }
+
+    class TestDisplayDevice extends DisplayDevice {
+        private DisplayDeviceInfo mInfo = new DisplayDeviceInfo();
+        private DisplayDeviceInfo mSentInfo;
+
+        TestDisplayDevice() {
+            super(null, null, "test_display_" + sUniqueTestDisplayId++, mContext);
+            mInfo = new DisplayDeviceInfo();
+        }
+
+        @Override
+        public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
+            if (mSentInfo == null) {
+                mSentInfo = new DisplayDeviceInfo();
+                mSentInfo.copyFrom(mInfo);
+            }
+            return mSentInfo;
+        }
+
+        @Override
+        public void applyPendingDisplayDeviceInfoChangesLocked() {
+            mSentInfo = null;
+        }
+
+        @Override
+        public boolean hasStableUniqueId() {
+            return true;
+        }
+
+        public DisplayDeviceInfo getSourceInfo() {
+            return mInfo;
+        }
+    }
+}
+
diff --git a/services/tests/servicestests/src/com/android/server/graphics/fonts/FontCrashDetectorTest.java b/services/tests/servicestests/src/com/android/server/graphics/fonts/FontCrashDetectorTest.java
deleted file mode 100644
index 275e7c7..0000000
--- a/services/tests/servicestests/src/com/android/server/graphics/fonts/FontCrashDetectorTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.graphics.fonts;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-import android.os.FileUtils;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.File;
-
-@Presubmit
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public final class FontCrashDetectorTest {
-
-    private File mCacheDir;
-
-    @SuppressWarnings("ResultOfMethodCallIgnored")
-    @Before
-    public void setUp() {
-        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-        mCacheDir = new File(context.getCacheDir(), "UpdatableFontDirTest");
-        FileUtils.deleteContentsAndDir(mCacheDir);
-        mCacheDir.mkdirs();
-    }
-
-    @Test
-    public void detectCrash() throws Exception {
-        // Prepare a marker file.
-        File file = new File(mCacheDir, "detectCrash");
-        assertThat(file.createNewFile()).isTrue();
-
-        FontCrashDetector detector = new FontCrashDetector(file);
-        assertThat(detector.hasCrashed()).isTrue();
-
-        detector.clear();
-        assertThat(detector.hasCrashed()).isFalse();
-        assertThat(file.exists()).isFalse();
-    }
-
-    @Test
-    public void monitorCrash() {
-        File file = new File(mCacheDir, "monitorCrash");
-        FontCrashDetector detector = new FontCrashDetector(file);
-        assertThat(detector.hasCrashed()).isFalse();
-
-        FontCrashDetector.MonitoredBlock block = detector.start();
-        assertThat(file.exists()).isTrue();
-
-        block.close();
-        assertThat(file.exists()).isFalse();
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/graphics/fonts/PersistentSystemFontConfigTest.java b/services/tests/servicestests/src/com/android/server/graphics/fonts/PersistentSystemFontConfigTest.java
index 27fce3c..912da94 100644
--- a/services/tests/servicestests/src/com/android/server/graphics/fonts/PersistentSystemFontConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/graphics/fonts/PersistentSystemFontConfigTest.java
@@ -45,7 +45,7 @@
     public void testWriteRead() throws Exception {
         long expectedModifiedDate = 1234567890;
         PersistentSystemFontConfig.Config config = new PersistentSystemFontConfig.Config();
-        config.lastModifiedDate = expectedModifiedDate;
+        config.lastModifiedMillis = expectedModifiedDate;
         config.updatedFontDirs.add("~~abc");
         config.updatedFontDirs.add("~~def");
 
@@ -65,7 +65,7 @@
                 PersistentSystemFontConfig.Config another = new PersistentSystemFontConfig.Config();
                 PersistentSystemFontConfig.loadFromXml(bais, another);
 
-                assertThat(another.lastModifiedDate).isEqualTo(expectedModifiedDate);
+                assertThat(another.lastModifiedMillis).isEqualTo(expectedModifiedDate);
                 assertThat(another.updatedFontDirs).containsExactly("~~abc", "~~def");
                 assertThat(another.fontFamilies).containsExactly(fontFamily);
             }
@@ -82,7 +82,7 @@
                      new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))) {
             PersistentSystemFontConfig.Config config = new PersistentSystemFontConfig.Config();
             PersistentSystemFontConfig.loadFromXml(bais, config);
-            assertThat(config.lastModifiedDate).isEqualTo(0);
+            assertThat(config.lastModifiedMillis).isEqualTo(0);
         }
     }
 
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 7771afc..843296e 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
@@ -151,7 +151,7 @@
         FakeFontFileParser parser = new FakeFontFileParser();
         FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
         PersistentSystemFontConfig.Config config = new PersistentSystemFontConfig.Config();
-        config.lastModifiedDate = expectedModifiedDate;
+        config.lastModifiedMillis = expectedModifiedDate;
         writeConfig(config, mConfigFile);
         UpdatableFontDir dirForPreparation = new UpdatableFontDir(
                 mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
@@ -507,7 +507,7 @@
         File readonlyFile = new File(readonlyDir, "readonly_config.xml");
 
         PersistentSystemFontConfig.Config config = new PersistentSystemFontConfig.Config();
-        config.lastModifiedDate = expectedModifiedDate;
+        config.lastModifiedMillis = expectedModifiedDate;
         writeConfig(config, readonlyFile);
 
         assertThat(readonlyDir.setWritable(false, false)).isTrue();
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 f2254a9..c08857c 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
@@ -74,8 +74,6 @@
         when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
-        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
-
         mHdmiControlService = new HdmiControlService(mContextSpy) {
             @Override
             AudioManager getAudioManager() {
@@ -106,15 +104,11 @@
             protected void writeStringSystemProperty(String key, String value) {
                 // do nothing
             }
-
-            @Override
-            protected HdmiCecConfig getHdmiCecConfig() {
-                return hdmiCecConfig;
-            }
         };
 
         Looper looper = mTestLooper.getLooper();
         mHdmiControlService.setIoLooper(looper);
+        mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
         mNativeWrapper = new FakeNativeWrapper();
         HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
                 this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
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 44418ce..50ba761 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
@@ -76,8 +76,6 @@
         when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
-        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
-
         HdmiControlService hdmiControlService =
                 new HdmiControlService(mContextSpy) {
                     @Override
@@ -112,11 +110,6 @@
                     Looper getServiceLooper() {
                         return mTestLooper.getLooper();
                     }
-
-                    @Override
-                    protected HdmiCecConfig getHdmiCecConfig() {
-                        return hdmiCecConfig;
-                    }
                 };
 
         mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(hdmiControlService) {
@@ -128,6 +121,7 @@
         mHdmiCecLocalDeviceAudioSystem.init();
         Looper looper = mTestLooper.getLooper();
         hdmiControlService.setIoLooper(looper);
+        hdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
         mNativeWrapper = new FakeNativeWrapper();
         HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
                 hdmiControlService, mNativeWrapper, hdmiControlService.getAtomWriter());
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 d454d87..aa5bc93 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
@@ -77,8 +77,6 @@
         when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
-        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
-
         HdmiControlService hdmiControlService =
                 new HdmiControlService(mContextSpy) {
                     @Override
@@ -113,15 +111,11 @@
                     Looper getServiceLooper() {
                         return mTestLooper.getLooper();
                     }
-
-                    @Override
-                    protected HdmiCecConfig getHdmiCecConfig() {
-                        return hdmiCecConfig;
-                    }
                 };
 
         Looper looper = mTestLooper.getLooper();
         hdmiControlService.setIoLooper(looper);
+        hdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
         mNativeWrapper = new FakeNativeWrapper();
         HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
                 hdmiControlService, mNativeWrapper, hdmiControlService.getAtomWriter());
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 7cb72c4..ef7b274 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
@@ -86,8 +86,6 @@
         when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
-        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
-
         mHdmiControlService = new HdmiControlService(mContextSpy) {
             @Override
             AudioManager getAudioManager() {
@@ -118,15 +116,11 @@
             protected void writeStringSystemProperty(String key, String value) {
                 // do nothing
             }
-
-            @Override
-            protected HdmiCecConfig getHdmiCecConfig() {
-                return hdmiCecConfig;
-            }
         };
 
         Looper looper = mTestLooper.getLooper();
         mHdmiControlService.setIoLooper(looper);
+        mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
         mNativeWrapper = new FakeNativeWrapper();
         HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
                 this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
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 9bf95c0..678f8b2 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java
@@ -106,8 +106,6 @@
         PowerManager powerManager = new PowerManager(context, mIPowerManagerMock,
                 mIThermalServiceMock, new Handler(mMyLooper));
 
-        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context);
-
         mHdmiControlService =
                 new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
                     @Override
@@ -133,16 +131,12 @@
                     protected PowerManager getPowerManager() {
                         return powerManager;
                     }
-
-                    @Override
-                    protected HdmiCecConfig getHdmiCecConfig() {
-                        return hdmiCecConfig;
-                    }
                 };
 
         mHdmiCecLocalDeviceTv = new HdmiCecLocalDeviceTv(mHdmiControlService);
         mHdmiCecLocalDeviceTv.init();
         mHdmiControlService.setIoLooper(mMyLooper);
+        mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
         mNativeWrapper = new FakeNativeWrapper();
         mHdmiCecController = HdmiCecController.createWithNativeWrapper(
                 mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
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 eedbc95..6bb148d 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -98,8 +98,6 @@
         PowerManager powerManager = new PowerManager(context, mIPowerManagerMock,
                 mIThermalServiceMock, new Handler(mMyLooper));
 
-        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context);
-
         mHdmiControlService =
             new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
                 @Override
@@ -188,17 +186,13 @@
                 protected PowerManager getPowerManager() {
                     return powerManager;
                 }
-
-                @Override
-                protected HdmiCecConfig getHdmiCecConfig() {
-                    return hdmiCecConfig;
-                }
             };
 
         mHdmiControlService.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
                 HdmiControlManager.VOLUME_CONTROL_ENABLED);
         mMyLooper = mTestLooper.getLooper();
+        mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
         mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(mHdmiControlService);
         mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService) {
             @Override
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 b11ac24..915392e 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -87,7 +87,6 @@
         mMyLooper = mTestLooper.getLooper();
         PowerManager powerManager = new PowerManager(context, mIPowerManagerMock,
                 mIThermalServiceMock, new Handler(mMyLooper));
-        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context);
 
         mHdmiControlService =
                 new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
@@ -136,15 +135,11 @@
                     protected PowerManager getPowerManager() {
                         return powerManager;
                     }
-
-                    @Override
-                    protected HdmiCecConfig getHdmiCecConfig() {
-                        return hdmiCecConfig;
-                    }
                 };
 
         mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService);
         mHdmiCecLocalDevicePlayback.init();
+        mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
         mHdmiControlService.setIoLooper(mMyLooper);
         mNativeWrapper = new FakeNativeWrapper();
         mHdmiCecController = HdmiCecController.createWithNativeWrapper(
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
index 0717112..b3f0085 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
@@ -128,8 +128,6 @@
 
         Context context = InstrumentationRegistry.getTargetContext();
 
-        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context);
-
         mHdmiControlService =
                 new HdmiControlService(context) {
                     @Override
@@ -163,13 +161,9 @@
                     void wakeUp() {
                         mWakeupMessageReceived = true;
                     }
-
-                    @Override
-                    protected HdmiCecConfig getHdmiCecConfig() {
-                        return hdmiCecConfig;
-                    }
                 };
         mHdmiControlService.setIoLooper(mTestLooper.getLooper());
+        mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
         mNativeWrapper = new FakeNativeWrapper();
         mHdmiCecController = HdmiCecController.createWithNativeWrapper(
                 mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
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 4623eb5..4b3ef2f 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -81,8 +81,6 @@
         PowerManager powerManager = new PowerManager(context, mIPowerManagerMock,
                 mIThermalServiceMock, new Handler(mMyLooper));
 
-        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context);
-
         mHdmiControlService =
                 new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
                     @Override
@@ -119,16 +117,12 @@
                     AudioManager getAudioManager() {
                         return mAudioManager;
                     }
-
-                    @Override
-                    protected HdmiCecConfig getHdmiCecConfig() {
-                        return hdmiCecConfig;
-                    }
                 };
 
         mHdmiCecLocalDeviceTv = new HdmiCecLocalDeviceTv(mHdmiControlService);
         mHdmiCecLocalDeviceTv.init();
         mHdmiControlService.setIoLooper(mMyLooper);
+        mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
         mNativeWrapper = new FakeNativeWrapper();
         mHdmiCecController = HdmiCecController.createWithNativeWrapper(
                 mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
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 06373c2..1c7ff42 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
@@ -62,12 +62,12 @@
     private FakeNativeWrapper mNativeWrapper;
     private TestLooper mTestLooper = new TestLooper();
     private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
-    private int mHdmiCecVersion = HdmiControlManager.HDMI_CEC_VERSION_1_4_B;
     @Mock
     private IPowerManager mIPowerManagerMock;
     @Mock
     private IThermalService mIThermalServiceMock;
     private HdmiControlService mHdmiControlService;
+    private HdmiCecLocalDevicePlayback mHdmiCecLocalDevicePlayback;
 
     @Before
     public void setUp() throws Exception {
@@ -81,8 +81,6 @@
         when(contextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
-        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(contextSpy);
-
         mHdmiControlService = new HdmiControlService(contextSpy) {
             @Override
             boolean isControlEnabled() {
@@ -100,33 +98,24 @@
             }
 
             @Override
-            int getCecVersion() {
-                return mHdmiCecVersion;
-            }
-
-            @Override
             boolean isPowerStandby() {
                 return false;
             }
-
-            @Override
-            protected HdmiCecConfig getHdmiCecConfig() {
-                return hdmiCecConfig;
-            }
         };
         mHdmiControlService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
 
-        HdmiCecLocalDevicePlayback hdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(
+        mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(
                 mHdmiControlService);
-        hdmiCecLocalDevicePlayback.init();
+        mHdmiCecLocalDevicePlayback.init();
         mHdmiControlService.setIoLooper(myLooper);
+        mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(contextSpy));
         mNativeWrapper = new FakeNativeWrapper();
         HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
                 mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
         mHdmiControlService.setCecController(hdmiCecController);
         mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
         mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
-        mLocalDevices.add(hdmiCecLocalDevicePlayback);
+        mLocalDevices.add(mHdmiCecLocalDevicePlayback);
         HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[1];
         hdmiPortInfos[0] =
                 new HdmiPortInfo(1, HdmiPortInfo.PORT_OUTPUT, 0x0000, true, false, false);
@@ -188,77 +177,84 @@
 
     @Test
     public void setPowerStatus_doesntSendBroadcast_1_4() {
+        setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
         mHdmiCecPowerStatusController.setPowerStatus(HdmiControlManager.POWER_STATUS_ON);
         mTestLooper.dispatchAll();
 
         HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
-                Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST,
+                mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST,
                 HdmiControlManager.POWER_STATUS_ON);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportPowerStatus);
     }
 
     @Test
     public void setPowerStatus_transient_doesntSendBroadcast_1_4() {
+        setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
         mHdmiCecPowerStatusController.setPowerStatus(
                 HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
         mTestLooper.dispatchAll();
 
         HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
-                Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST,
+                mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST,
                 HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportPowerStatus);
     }
 
     @Test
     public void setPowerStatus_fast_transient_doesntSendBroadcast_1_4() {
+        setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
         mHdmiCecPowerStatusController.setPowerStatus(
                 HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON, false);
         mTestLooper.dispatchAll();
 
         HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
-                Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST,
+                mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST,
                 HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportPowerStatus);
     }
 
     @Test
     public void setPowerStatus_sendsBroadcast_2_0() {
-        mHdmiCecVersion = HdmiControlManager.HDMI_CEC_VERSION_2_0;
-
+        setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0);
         mHdmiCecPowerStatusController.setPowerStatus(HdmiControlManager.POWER_STATUS_ON);
         mTestLooper.dispatchAll();
 
         HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
-                Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST,
+                mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST,
                 HdmiControlManager.POWER_STATUS_ON);
         assertThat(mNativeWrapper.getResultMessages()).contains(reportPowerStatus);
     }
 
     @Test
     public void setPowerStatus_transient_sendsBroadcast_2_0() {
-        mHdmiCecVersion = HdmiControlManager.HDMI_CEC_VERSION_2_0;
-
+        setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0);
         mHdmiCecPowerStatusController.setPowerStatus(
                 HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
         mTestLooper.dispatchAll();
 
         HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
-                Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST,
+                mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST,
                 HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
         assertThat(mNativeWrapper.getResultMessages()).contains(reportPowerStatus);
     }
 
     @Test
     public void setPowerStatus_fast_transient_doesntSendBroadcast_2_0() {
-        mHdmiCecVersion = HdmiControlManager.HDMI_CEC_VERSION_2_0;
-
+        setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0);
         mHdmiCecPowerStatusController.setPowerStatus(
                 HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON, false);
         mTestLooper.dispatchAll();
 
         HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
-                Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST,
+                mHdmiCecLocalDevicePlayback.mAddress, Constants.ADDR_BROADCAST,
                 HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportPowerStatus);
     }
+
+    private void setCecVersion(int version) {
+        mHdmiControlService.getHdmiCecConfig().setIntValue(
+                HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION, version);
+        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+        mTestLooper.dispatchAll();
+    }
 }
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 32a7048..47f3bf9 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -19,6 +19,7 @@
 import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_PLAYBACK;
 
 import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
+import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
 import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -44,12 +45,12 @@
 import android.os.test.TestLooper;
 import android.platform.test.annotations.Presubmit;
 import android.provider.Settings;
+import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -68,14 +69,64 @@
 @RunWith(JUnit4.class)
 public class HdmiControlServiceTest {
 
-    private class HdmiCecLocalDeviceMyDevice extends HdmiCecLocalDeviceSource {
+    private class MockPlaybackDevice extends HdmiCecLocalDevicePlayback {
 
         private boolean mCanGoToStandby;
         private boolean mIsStandby;
         private boolean mIsDisabled;
 
-        protected HdmiCecLocalDeviceMyDevice(HdmiControlService service, int deviceType) {
-            super(service, deviceType);
+        MockPlaybackDevice(HdmiControlService service) {
+            super(service);
+        }
+
+        @Override
+        protected void onAddressAllocated(int logicalAddress, int reason) {}
+
+        @Override
+        protected int getPreferredAddress() {
+            return 0;
+        }
+
+        @Override
+        protected void setPreferredAddress(int addr) {}
+
+        @Override
+        protected boolean canGoToStandby() {
+            return mCanGoToStandby;
+        }
+
+        @Override
+        protected void disableDevice(
+                boolean initiatedByCec, final PendingActionClearedCallback originalCallback) {
+            mIsDisabled = true;
+            originalCallback.onCleared(this);
+        }
+
+        @Override
+        protected void onStandby(boolean initiatedByCec, int standbyAction) {
+            mIsStandby = true;
+        }
+
+        protected boolean isStandby() {
+            return mIsStandby;
+        }
+
+        protected boolean isDisabled() {
+            return mIsDisabled;
+        }
+
+        protected void setCanGoToStandby(boolean canGoToStandby) {
+            mCanGoToStandby = canGoToStandby;
+        }
+    }
+    private class MockAudioSystemDevice extends HdmiCecLocalDeviceAudioSystem {
+
+        private boolean mCanGoToStandby;
+        private boolean mIsStandby;
+        private boolean mIsDisabled;
+
+        MockAudioSystemDevice(HdmiControlService service) {
+            super(service);
         }
 
         @Override
@@ -123,8 +174,8 @@
     private Context mContextSpy;
     private HdmiControlService mHdmiControlService;
     private HdmiCecController mHdmiCecController;
-    private HdmiCecLocalDeviceMyDevice mMyAudioSystemDevice;
-    private HdmiCecLocalDeviceMyDevice mMyPlaybackDevice;
+    private MockAudioSystemDevice mAudioSystemDevice;
+    private MockPlaybackDevice mPlaybackDevice;
     private FakeNativeWrapper mNativeWrapper;
     private Looper mMyLooper;
     private TestLooper mTestLooper = new TestLooper();
@@ -144,6 +195,7 @@
         PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock,
                 mIThermalServiceMock, null);
         when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager);
+        when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
         HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
@@ -157,21 +209,17 @@
             @Override
             protected void writeStringSystemProperty(String key, String value) {
             }
-
-            @Override
-            protected HdmiCecConfig getHdmiCecConfig() {
-                return hdmiCecConfig;
-            }
         };
         mMyLooper = mTestLooper.getLooper();
 
-        mMyAudioSystemDevice =
-                new HdmiCecLocalDeviceMyDevice(mHdmiControlService, DEVICE_AUDIO_SYSTEM);
-        mMyPlaybackDevice = new HdmiCecLocalDeviceMyDevice(mHdmiControlService, DEVICE_PLAYBACK);
-        mMyAudioSystemDevice.init();
-        mMyPlaybackDevice.init();
+        mAudioSystemDevice = new MockAudioSystemDevice(mHdmiControlService);
+        mPlaybackDevice = new MockPlaybackDevice(mHdmiControlService);
+        mAudioSystemDevice.init();
+        mPlaybackDevice.init();
 
         mHdmiControlService.setIoLooper(mMyLooper);
+        mHdmiControlService.setHdmiCecConfig(hdmiCecConfig);
+        mHdmiControlService.onBootPhase(PHASE_SYSTEM_SERVICES_READY);
 
         mNativeWrapper = new FakeNativeWrapper();
         mHdmiCecController = HdmiCecController.createWithNativeWrapper(
@@ -180,8 +228,8 @@
         mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
         mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
 
-        mLocalDevices.add(mMyAudioSystemDevice);
-        mLocalDevices.add(mMyPlaybackDevice);
+        mLocalDevices.add(mAudioSystemDevice);
+        mLocalDevices.add(mPlaybackDevice);
         mHdmiPortInfo = new HdmiPortInfo[4];
         mHdmiPortInfo[0] =
             new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, 0x2100, true, false, false);
@@ -192,6 +240,9 @@
         mHdmiPortInfo[3] =
             new HdmiPortInfo(4, HdmiPortInfo.PORT_INPUT, 0x3000, true, false, false);
         mNativeWrapper.setPortInfo(mHdmiPortInfo);
+        mHdmiControlService.getHdmiCecConfig().setIntValue(
+                HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+                HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
         mHdmiControlService.initService();
         mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
 
@@ -201,13 +252,13 @@
     @Test
     public void onStandby_notByCec_cannotGoToStandby() {
         mStandbyMessageReceived = false;
-        mMyPlaybackDevice.setCanGoToStandby(false);
+        mPlaybackDevice.setCanGoToStandby(false);
 
         mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF);
-        assertTrue(mMyPlaybackDevice.isStandby());
-        assertTrue(mMyAudioSystemDevice.isStandby());
-        assertFalse(mMyPlaybackDevice.isDisabled());
-        assertFalse(mMyAudioSystemDevice.isDisabled());
+        assertTrue(mPlaybackDevice.isStandby());
+        assertTrue(mAudioSystemDevice.isStandby());
+        assertFalse(mPlaybackDevice.isDisabled());
+        assertFalse(mAudioSystemDevice.isDisabled());
     }
 
     @Test
@@ -215,10 +266,10 @@
         mStandbyMessageReceived = true;
 
         mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF);
-        assertTrue(mMyPlaybackDevice.isStandby());
-        assertTrue(mMyAudioSystemDevice.isStandby());
-        assertTrue(mMyPlaybackDevice.isDisabled());
-        assertTrue(mMyAudioSystemDevice.isDisabled());
+        assertTrue(mPlaybackDevice.isStandby());
+        assertTrue(mAudioSystemDevice.isStandby());
+        assertTrue(mPlaybackDevice.isDisabled());
+        assertTrue(mAudioSystemDevice.isDisabled());
     }
 
     @Test
@@ -275,6 +326,7 @@
         mHdmiControlService.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
+        mTestLooper.dispatchAll();
 
         mHdmiControlService.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
         mNativeWrapper.clearResultMessages();
@@ -555,8 +607,8 @@
         HdmiCecMessage reportFeatures = HdmiCecMessageBuilder.buildReportFeatures(
                 Constants.ADDR_PLAYBACK_1, HdmiControlManager.HDMI_CEC_VERSION_2_0,
                 Arrays.asList(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM),
-                mMyPlaybackDevice.getRcProfile(), mMyPlaybackDevice.getRcFeatures(),
-                mMyPlaybackDevice.getDeviceFeatures());
+                mPlaybackDevice.getRcProfile(), mPlaybackDevice.getRcFeatures(),
+                mPlaybackDevice.getDeviceFeatures());
         assertThat(mNativeWrapper.getResultMessages()).contains(reportFeatures);
     }
 
@@ -573,8 +625,8 @@
         HdmiCecMessage reportFeatures = HdmiCecMessageBuilder.buildReportFeatures(
                 Constants.ADDR_PLAYBACK_1, HdmiControlManager.HDMI_CEC_VERSION_2_0,
                 Arrays.asList(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM),
-                mMyPlaybackDevice.getRcProfile(), mMyPlaybackDevice.getRcFeatures(),
-                mMyPlaybackDevice.getDeviceFeatures());
+                mPlaybackDevice.getRcProfile(), mPlaybackDevice.getRcFeatures(),
+                mPlaybackDevice.getDeviceFeatures());
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportFeatures);
     }
 
@@ -590,8 +642,8 @@
         HdmiCecMessage reportFeatures = HdmiCecMessageBuilder.buildReportFeatures(
                 Constants.ADDR_PLAYBACK_1, HdmiControlManager.HDMI_CEC_VERSION_2_0,
                 Arrays.asList(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM),
-                mMyPlaybackDevice.getRcProfile(), mMyPlaybackDevice.getRcFeatures(),
-                mMyPlaybackDevice.getDeviceFeatures());
+                mPlaybackDevice.getRcProfile(), mPlaybackDevice.getRcFeatures(),
+                mPlaybackDevice.getDeviceFeatures());
         assertThat(mNativeWrapper.getResultMessages()).contains(reportFeatures);
     }
 
@@ -612,41 +664,42 @@
         assertEquals(runnerUid, Binder.getCallingWorkSourceUid());
     }
 
-    @Ignore("b/180499471")
     @Test
     public void initCecVersion_limitToMinimumSupportedVersion() {
+        mNativeWrapper.setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
+        Log.e("MARVIN", "set setting CEC");
         mHdmiControlService.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
-        mNativeWrapper.setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
 
-        mHdmiControlService.initService();
+        mTestLooper.dispatchAll();
         assertThat(mHdmiControlService.getCecVersion()).isEqualTo(
                 HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
     }
 
-    @Ignore("b/180499471")
     @Test
     public void initCecVersion_limitToAtLeast1_4() {
+        Log.e("MARVIN", "set HAL CEC to 0");
+        mNativeWrapper.setCecVersion(0x0);
+        Log.e("MARVIN", "set setting CEC to 2");
         mHdmiControlService.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
-        mNativeWrapper.setCecVersion(0x0);
 
-        mHdmiControlService.initService();
+        mTestLooper.dispatchAll();
         assertThat(mHdmiControlService.getCecVersion()).isEqualTo(
                 HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
     }
 
-    @Ignore("b/180499471")
     @Test
     public void initCecVersion_useHighestMatchingVersion() {
+        mNativeWrapper.setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0);
+        Log.e("MARVIN", "set setting CEC");
         mHdmiControlService.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
-        mNativeWrapper.setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0);
 
-        mHdmiControlService.initService();
+        mTestLooper.dispatchAll();
         assertThat(mHdmiControlService.getCecVersion()).isEqualTo(
                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
     }
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 b8dfd56..605f781 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
@@ -84,8 +84,6 @@
         when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
-        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
-
         mHdmiControlService = new HdmiControlService(mContextSpy) {
             @Override
             AudioManager getAudioManager() {
@@ -116,15 +114,11 @@
             protected void writeStringSystemProperty(String key, String value) {
                 // do nothing
             }
-
-            @Override
-            protected HdmiCecConfig getHdmiCecConfig() {
-                return hdmiCecConfig;
-            }
         };
 
         Looper looper = mTestLooper.getLooper();
         mHdmiControlService.setIoLooper(looper);
+        mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
         mNativeWrapper = new FakeNativeWrapper();
         HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
                 this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
@@ -185,6 +179,7 @@
         mHdmiControlService.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
+        mTestLooper.dispatchAll();
         sendMessageFromPlaybackDevice(ADDR_PLAYBACK_1, 0x1000);
         reportPowerStatus(ADDR_PLAYBACK_1, true, HdmiControlManager.POWER_STATUS_ON);
         mTestLooper.dispatchAll();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
index f9160ab..e82c788 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
@@ -65,8 +65,6 @@
 
         Context context = InstrumentationRegistry.getTargetContext();
 
-        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context);
-
         HdmiControlService hdmiControlService = new HdmiControlService(context) {
                     @Override
                     void sendCecCommand(
@@ -164,15 +162,11 @@
                     int pathToPortId(int path) {
                         return -1;
                     }
-
-                    @Override
-                    protected HdmiCecConfig getHdmiCecConfig() {
-                        return hdmiCecConfig;
-                    }
                 };
 
         Looper looper = mTestLooper.getLooper();
         hdmiControlService.setIoLooper(looper);
+        hdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
         HdmiCecController.NativeWrapper nativeWrapper = new FakeNativeWrapper();
         HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
                 hdmiControlService, nativeWrapper, hdmiControlService.getAtomWriter());
diff --git a/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java b/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
index f87d599..7d9ab37 100644
--- a/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
@@ -20,8 +20,10 @@
 import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BG;
 import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BGUSER;
 import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_EJ;
+import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_FGS;
 import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_NONE;
 import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_TOP;
+import static com.android.server.job.JobConcurrencyManager.workTypeToString;
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
@@ -54,7 +56,7 @@
 
     private static final double[] EQUAL_PROBABILITY_CDF =
             buildWorkTypeCdf(1.0 / NUM_WORK_TYPES, 1.0 / NUM_WORK_TYPES, 1.0 / NUM_WORK_TYPES,
-                    1.0 / NUM_WORK_TYPES);
+                    1.0 / NUM_WORK_TYPES, 1.0 / NUM_WORK_TYPES);
 
     private Random mRandom;
     private WorkCountTracker mWorkCountTracker;
@@ -66,8 +68,9 @@
     }
 
     @NonNull
-    private static double[] buildWorkTypeCdf(double pTop, double pEj, double pBg, double pBgUser) {
-        return buildCdf(pTop, pEj, pBg, pBgUser);
+    private static double[] buildWorkTypeCdf(
+            double pTop, double pFgs, double pEj, double pBg, double pBgUser) {
+        return buildCdf(pTop, pFgs, pEj, pBg, pBgUser);
     }
 
     @NonNull
@@ -102,10 +105,12 @@
             case 0:
                 return WORK_TYPE_TOP;
             case 1:
-                return WORK_TYPE_EJ;
+                return WORK_TYPE_FGS;
             case 2:
-                return WORK_TYPE_BG;
+                return WORK_TYPE_EJ;
             case 3:
+                return WORK_TYPE_BG;
+            case 4:
                 return WORK_TYPE_BGUSER;
             default:
                 throw new IllegalStateException("Unknown work type");
@@ -224,12 +229,15 @@
 
     private void startPendingJobs(Jobs jobs) {
         while (hasStartablePendingJob(jobs)) {
-            final int startingWorkType =
-                    getRandomWorkType(EQUAL_PROBABILITY_CDF, mRandom.nextDouble());
+            final int workType = getRandomWorkType(EQUAL_PROBABILITY_CDF, mRandom.nextDouble());
 
-            if (jobs.pending.get(startingWorkType) > 0
-                    && mWorkCountTracker.canJobStart(startingWorkType) != WORK_TYPE_NONE) {
-                final int pendingMultiType = getPendingMultiType(jobs, startingWorkType);
+            if (jobs.pending.get(workType) > 0) {
+                final int pendingMultiType = getPendingMultiType(jobs, workType);
+                final int startingWorkType = mWorkCountTracker.canJobStart(pendingMultiType);
+                if (startingWorkType == WORK_TYPE_NONE) {
+                    continue;
+                }
+
                 jobs.removePending(pendingMultiType);
                 jobs.running.put(startingWorkType, jobs.running.get(startingWorkType) + 1);
                 mWorkCountTracker.stageJob(startingWorkType, pendingMultiType);
@@ -304,7 +312,7 @@
                 List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
         final List<Pair<Integer, Integer>> minLimits = List.of();
         final double probStop = 0.5;
-        final double[] cdf = buildWorkTypeCdf(0.5, 0, 0.5, 0);
+        final double[] cdf = buildWorkTypeCdf(0.5, 0, 0, 0.5, 0);
         final double[] numTypesCdf = buildCdf(.5, .3, .15, .05);
         final double probStart = 0.5;
 
@@ -322,7 +330,7 @@
                 List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
         final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
         final double probStop = 0.5;
-        final double[] cdf = buildWorkTypeCdf(1.0 / 3, 0, 1.0 / 3, 1.0 / 3);
+        final double[] cdf = buildWorkTypeCdf(1.0 / 3, 0, 0, 1.0 / 3, 1.0 / 3);
         final double[] numTypesCdf = buildCdf(.75, .2, .05);
         final double probStart = 0.5;
 
@@ -340,7 +348,7 @@
                 List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
         final List<Pair<Integer, Integer>> minLimits = List.of();
         final double probStop = 0.5;
-        final double[] cdf = buildWorkTypeCdf(1.0 / 3, 0, 1.0 / 3, 1.0 / 3);
+        final double[] cdf = buildWorkTypeCdf(1.0 / 3, 0, 0, 1.0 / 3, 1.0 / 3);
         final double[] numTypesCdf = buildCdf(.05, .95);
         final double probStart = 0.5;
 
@@ -358,7 +366,7 @@
                 List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
         final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
         final double probStop = 0.5;
-        final double[] cdf = buildWorkTypeCdf(0.1, 0, 0.8, .1);
+        final double[] cdf = buildWorkTypeCdf(0.1, 0, 0, 0.8, .1);
         final double[] numTypesCdf = buildCdf(.5, .3, .15, .05);
         final double probStart = 0.5;
 
@@ -376,7 +384,7 @@
                 List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
         final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
         final double probStop = 0.5;
-        final double[] cdf = buildWorkTypeCdf(0.9, 0, 0.1, 0);
+        final double[] cdf = buildWorkTypeCdf(0.85, 0.05, 0, 0.1, 0);
         final double[] numTypesCdf = buildCdf(1);
         final double probStart = 0.5;
 
@@ -394,7 +402,7 @@
                 List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
         final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
         final double probStop = 0.4;
-        final double[] cdf = buildWorkTypeCdf(0.1, 0, 0.1, .8);
+        final double[] cdf = buildWorkTypeCdf(0.1, 0, 0, 0.1, .8);
         final double[] numTypesCdf = buildCdf(0.5, 0.5);
         final double probStart = 0.5;
 
@@ -413,7 +421,7 @@
         final List<Pair<Integer, Integer>> minLimits =
                 List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
         final double probStop = 0.4;
-        final double[] cdf = buildWorkTypeCdf(0.9, 0, 0.05, 0.05);
+        final double[] cdf = buildWorkTypeCdf(0.8, 0.1, 0, 0.05, 0.05);
         final double[] numTypesCdf = buildCdf(1);
         final double probStart = 0.5;
 
@@ -432,7 +440,7 @@
         final List<Pair<Integer, Integer>> minLimits =
                 List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
         final double probStop = 0.5;
-        final double[] cdf = buildWorkTypeCdf(0, 0, 0.5, 0.5);
+        final double[] cdf = buildWorkTypeCdf(0, 0, 0, 0.5, 0.5);
         final double[] numTypesCdf = buildCdf(1);
         final double probStart = 0.5;
 
@@ -451,7 +459,7 @@
         final List<Pair<Integer, Integer>> minLimits =
                 List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
         final double probStop = 0.5;
-        final double[] cdf = buildWorkTypeCdf(0, 0, 0.1, 0.9);
+        final double[] cdf = buildWorkTypeCdf(0, 0, 0, 0.1, 0.9);
         final double[] numTypesCdf = buildCdf(0.9, 0.1);
         final double probStart = 0.5;
 
@@ -470,7 +478,7 @@
         final List<Pair<Integer, Integer>> minLimits =
                 List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
         final double probStop = 0.5;
-        final double[] cdf = buildWorkTypeCdf(0, 0, 0.9, 0.1);
+        final double[] cdf = buildWorkTypeCdf(0, 0, 0, 0.9, 0.1);
         final double[] numTypesCdf = buildCdf(1);
         final double probStart = 0.5;
 
@@ -488,7 +496,7 @@
         final List<Pair<Integer, Integer>> minLimits =
                 List.of(Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 2));
         final double probStop = 0.4;
-        final double[] cdf = buildWorkTypeCdf(0.5, 0.5, 0, 0);
+        final double[] cdf = buildWorkTypeCdf(0.5, 0, 0.5, 0, 0);
         final double[] numTypesCdf = buildCdf(0.1, 0.7, 0.2);
         final double probStart = 0.5;
 
@@ -511,7 +519,7 @@
         final List<Pair<Integer, Integer>> minLimits =
                 List.of(Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 1));
         final double probStop = 0.13;
-        final double[] numTypesCdf = buildCdf(0, 0.05, 0.1, 0.85);
+        final double[] numTypesCdf = buildCdf(0, 0.05, 0.1, 0.8, 0.05);
         final double probStart = 0.87;
 
         checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
@@ -528,7 +536,7 @@
                 List.of(Pair.create(WORK_TYPE_EJ, 5), Pair.create(WORK_TYPE_BG, 4));
         final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
         final double probStop = 0.4;
-        final double[] cdf = buildWorkTypeCdf(.1, 0.5, 0.35, 0.05);
+        final double[] cdf = buildWorkTypeCdf(.1, 0, 0.5, 0.35, 0.05);
         final double[] numTypesCdf = buildCdf(1);
         final double probStart = 0.5;
 
@@ -548,7 +556,7 @@
         final List<Pair<Integer, Integer>> minLimits =
                 List.of(Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2));
         final double probStop = 0.4;
-        final double[] cdf = buildWorkTypeCdf(0.01, 0.49, 0.1, 0.4);
+        final double[] cdf = buildWorkTypeCdf(0.01, 0.09, 0.4, 0.1, 0.4);
         final double[] numTypesCdf = buildCdf(0.7, 0.3);
         final double probStart = 0.5;
 
@@ -576,11 +584,13 @@
         startPendingJobs(jobs);
 
         for (Pair<Integer, Integer> run : resultRunning) {
-            assertWithMessage("Incorrect running result for work type " + run.first)
+            assertWithMessage(
+                    "Incorrect running result for work type " + workTypeToString(run.first))
                     .that(jobs.running.get(run.first)).isEqualTo(run.second);
         }
         for (Pair<Integer, Integer> pend : resultPending) {
-            assertWithMessage("Incorrect pending result for work type " + pend.first)
+            assertWithMessage(
+                    "Incorrect pending result for work type " + workTypeToString(pend.first))
                     .that(jobs.pending.get(pend.first)).isEqualTo(pend.second);
         }
     }
@@ -938,10 +948,15 @@
         assertThat(jobs.running.get(WORK_TYPE_TOP)).isEqualTo(6);
         assertThat(jobs.running.get(WORK_TYPE_EJ)).isEqualTo(1);
         assertThat(jobs.running.get(WORK_TYPE_BG)).isEqualTo(1);
-        assertThat(jobs.pending.get(WORK_TYPE_TOP)).isEqualTo(4);
+        // If run the TOP jobs as TOP first, and a TOP|EJ job as EJ, then we'll have 4 TOP jobs
+        // remaining.
+        assertThat(jobs.pending.get(WORK_TYPE_TOP)).isAtLeast(4);
+        // If we end up running the TOP|EJ jobs as TOP first, then we'll have 5 TOP jobs remaining.
+        assertThat(jobs.pending.get(WORK_TYPE_TOP)).isAtMost(5);
         // Can't equate pending EJ since some could be running as TOP and BG
         assertThat(jobs.pending.get(WORK_TYPE_EJ)).isAtLeast(2);
-        assertThat(jobs.pending.get(WORK_TYPE_BG)).isEqualTo(9);
+        assertThat(jobs.pending.get(WORK_TYPE_BG)).isAtLeast(8);
+        assertThat(jobs.pending.get(WORK_TYPE_BG)).isAtMost(9);
 
         // Stop all jobs
         jobs.maybeFinishJobs(1);
@@ -975,7 +990,7 @@
         assertThat(jobs.running.get(WORK_TYPE_EJ)).isAtLeast(1);
         assertThat(jobs.running.get(WORK_TYPE_BG)).isEqualTo(1);
         assertThat(jobs.pending.get(WORK_TYPE_TOP)).isEqualTo(0);
-        assertThat(jobs.pending.get(WORK_TYPE_EJ)).isAtLeast(2);
+        assertThat(jobs.pending.get(WORK_TYPE_EJ)).isAtLeast(1);
         assertThat(jobs.pending.get(WORK_TYPE_BG)).isEqualTo(4);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java b/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java
index 2288a89..cc18317 100644
--- a/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java
@@ -18,7 +18,9 @@
 import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BG;
 import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BGUSER;
 import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_EJ;
+import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_FGS;
 import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_TOP;
+import static com.android.server.job.JobConcurrencyManager.workTypeToString;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
@@ -44,10 +46,12 @@
 public class WorkTypeConfigTest {
     private static final String KEY_MAX_TOTAL = "concurrency_max_total_test";
     private static final String KEY_MAX_TOP = "concurrency_max_top_test";
+    private static final String KEY_MAX_FGS = "concurrency_max_fgs_test";
     private static final String KEY_MAX_EJ = "concurrency_max_ej_test";
     private static final String KEY_MAX_BG = "concurrency_max_bg_test";
     private static final String KEY_MAX_BGUSER = "concurrency_max_bguser_test";
     private static final String KEY_MIN_TOP = "concurrency_min_top_test";
+    private static final String KEY_MIN_FGS = "concurrency_min_fgs_test";
     private static final String KEY_MIN_EJ = "concurrency_min_ej_test";
     private static final String KEY_MIN_BG = "concurrency_min_bg_test";
     private static final String KEY_MIN_BGUSER = "concurrency_min_bguser_test";
@@ -59,15 +63,17 @@
 
     private void resetConfig() {
         // DeviceConfig.resetToDefaults() doesn't work here. Need to reset constants manually.
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_TOTAL, "", false);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_TOP, "", false);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_EJ, "", false);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_BG, "", false);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_BGUSER, "", false);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_TOP, "", false);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_EJ, "", false);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_BG, "", false);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_BGUSER, "", false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_TOTAL, null, false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_TOP, null, false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_FGS, null, false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_EJ, null, false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_BG, null, false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_BGUSER, null, false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_TOP, null, false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_FGS, null, false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_EJ, null, false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_BG, null, false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_BGUSER, null, false);
     }
 
     private void check(@Nullable DeviceConfig.Properties config,
@@ -103,10 +109,12 @@
 
         assertEquals(expectedTotal, counts.getMaxTotal());
         for (Pair<Integer, Integer> min : expectedMinLimits) {
-            assertEquals((int) min.second, counts.getMinReserved(min.first));
+            assertEquals("Incorrect min value for " + workTypeToString(min.first),
+                    (int) min.second, counts.getMinReserved(min.first));
         }
         for (Pair<Integer, Integer> max : expectedMaxLimits) {
-            assertEquals((int) max.second, counts.getMax(max.first));
+            assertEquals("Incorrect max value for " + workTypeToString(max.first),
+                    (int) max.second, counts.getMax(max.first));
         }
     }
 
@@ -193,6 +201,14 @@
                 /* min */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 3),
                         Pair.create(WORK_TYPE_BG, 1)),
                 /* max */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 1)));
+        check(null, /*default*/ 10,
+                /* min */ List.of(Pair.create(WORK_TYPE_TOP, 3), Pair.create(WORK_TYPE_FGS, 2),
+                        Pair.create(WORK_TYPE_EJ, 1), Pair.create(WORK_TYPE_BG, 1)),
+                /* max */ List.of(Pair.create(WORK_TYPE_FGS, 3)),
+                /*expected*/ true, 10,
+                /* min */ List.of(Pair.create(WORK_TYPE_TOP, 3), Pair.create(WORK_TYPE_FGS, 2),
+                        Pair.create(WORK_TYPE_EJ, 1), Pair.create(WORK_TYPE_BG, 1)),
+                /* max */ List.of(Pair.create(WORK_TYPE_FGS, 3)));
         check(null, /*default*/ 15,
                 /* min */ List.of(Pair.create(WORK_TYPE_BG, 15)),
                 /* max */ List.of(Pair.create(WORK_TYPE_BG, 15)),
@@ -289,5 +305,30 @@
                 /*expected*/ true, 16,
                 /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 8)),
                 /* max */ List.of(Pair.create(WORK_TYPE_TOP, 16), Pair.create(WORK_TYPE_BG, 16)));
+
+        check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
+                        .setInt(KEY_MAX_TOTAL, 16)
+                        .setInt(KEY_MAX_TOP, 16)
+                        .setInt(KEY_MIN_TOP, 1)
+                        .setInt(KEY_MAX_FGS, 15)
+                        .setInt(KEY_MIN_FGS, 2)
+                        .setInt(KEY_MAX_EJ, 14)
+                        .setInt(KEY_MIN_EJ, 3)
+                        .setInt(KEY_MAX_BG, 13)
+                        .setInt(KEY_MIN_BG, 4)
+                        .setInt(KEY_MAX_BGUSER, 12)
+                        .setInt(KEY_MIN_BGUSER, 5)
+                        .build(),
+                /*default*/ 9,
+                /* min */ List.of(Pair.create(WORK_TYPE_BG, 9)),
+                /* max */ List.of(Pair.create(WORK_TYPE_BG, 9)),
+                /*expected*/ true, 16,
+                /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_FGS, 2),
+                        Pair.create(WORK_TYPE_EJ, 3),
+                        Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 5)),
+                /* max */
+                List.of(Pair.create(WORK_TYPE_TOP, 16), Pair.create(WORK_TYPE_FGS, 15),
+                        Pair.create(WORK_TYPE_EJ, 14),
+                        Pair.create(WORK_TYPE_BG, 13), Pair.create(WORK_TYPE_BGUSER, 12)));
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
index 73191dc..4a42940 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -150,7 +150,7 @@
         }
 
         @Override
-        public RecoverableKeyStoreManager getRecoverableKeyStoreManager(KeyStore keyStore) {
+        public RecoverableKeyStoreManager getRecoverableKeyStoreManager() {
             return mRecoverableKeyStoreManager;
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 7d7af03..13c3919 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -115,7 +115,6 @@
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkPolicy;
-import android.net.NetworkPolicyManager;
 import android.net.NetworkState;
 import android.net.NetworkStats;
 import android.net.NetworkStatsHistory;
@@ -386,8 +385,7 @@
                 Log.d(TAG, "set mUidObserver to " + mUidObserver);
                 return null;
             }
-        }).when(mActivityManager).registerUidObserver(any(), anyInt(),
-                eq(NetworkPolicyManager.FOREGROUND_THRESHOLD_STATE), any(String.class));
+        }).when(mActivityManager).registerUidObserver(any(), anyInt(), anyInt(), any(String.class));
 
         mFutureIntent = newRestrictBackgroundChangedFuture();
         mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager,
@@ -2043,7 +2041,8 @@
         final NetworkCapabilities networkCapabilities = new NetworkCapabilities();
         networkCapabilities.addTransportType(TRANSPORT_WIFI);
         networkCapabilities.setSSID(TEST_SSID);
-        return new NetworkState(TYPE_WIFI, prop, networkCapabilities, null, null);
+        return new NetworkState(TYPE_WIFI, prop, networkCapabilities, new Network(TEST_NET_ID),
+                null);
     }
 
     private void expectHasInternetPermission(int uid, boolean hasIt) throws Exception {
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 e46ab6b..029e9a3 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -45,6 +45,13 @@
 import android.app.IUidObserver;
 import android.app.Person;
 import android.app.admin.DevicePolicyManager;
+import android.app.appsearch.AppSearchBatchResult;
+import android.app.appsearch.AppSearchManager;
+import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.IAppSearchBatchResultCallback;
+import android.app.appsearch.IAppSearchManager;
+import android.app.appsearch.IAppSearchResultCallback;
+import android.app.appsearch.PackageIdentifier;
 import android.app.role.OnRoleHoldersChangedListener;
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.ActivityNotFoundException;
@@ -78,6 +85,7 @@
 import android.os.Bundle;
 import android.os.FileUtils;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Looper;
 import android.os.PersistableBundle;
 import android.os.Process;
@@ -150,6 +158,8 @@
                     return mMockUserManager;
                 case Context.DEVICE_POLICY_SERVICE:
                     return mMockDevicePolicyManager;
+                case Context.APP_SEARCH_SERVICE:
+                    return new AppSearchManager(getTestContext(), mMockAppSearchManager);
                 case Context.ROLE_SERVICE:
                     // RoleManager is final and cannot be mocked, so we only override the inject
                     // accessor methods in ShortcutService.
@@ -159,6 +169,11 @@
         }
 
         @Override
+        public String getOpPackageName() {
+            return getTestContext().getOpPackageName();
+        }
+
+        @Override
         public String getSystemServiceName(Class<?> serviceClass) {
             return getTestContext().getSystemServiceName(serviceClass);
         }
@@ -601,6 +616,123 @@
         }
     }
 
+    protected class MockAppSearchManager implements IAppSearchManager {
+
+        protected Map<String, List<PackageIdentifier>> mSchemasPackageAccessible =
+                new ArrayMap<>(1);
+
+        @Override
+        public void setSchema(String packageName, String databaseName, List<Bundle> schemaBundles,
+                List<String> schemasNotPlatformSurfaceable,
+                Map<String, List<Bundle>> schemasPackageAccessibleBundles, boolean forceOverride,
+                int userId, IAppSearchResultCallback callback) throws RemoteException {
+            for (Map.Entry<String, List<Bundle>> entry :
+                    schemasPackageAccessibleBundles.entrySet()) {
+                final String key = entry.getKey();
+                final List<PackageIdentifier> packageIdentifiers;
+                if (!mSchemasPackageAccessible.containsKey(key)) {
+                    packageIdentifiers = new ArrayList<>(entry.getValue().size());
+                    mSchemasPackageAccessible.put(key, packageIdentifiers);
+                } else {
+                    packageIdentifiers = mSchemasPackageAccessible.get(key);
+                }
+                for (int i = 0; i < entry.getValue().size(); i++) {
+                    packageIdentifiers.add(new PackageIdentifier(entry.getValue().get(i)));
+                }
+            }
+            callback.onResult(AppSearchResult.newSuccessfulResult(null));
+        }
+
+        @Override
+        public void getSchema(String packageName, String databaseName, int userId,
+                IAppSearchResultCallback callback) throws RemoteException {
+            ignore(callback);
+        }
+
+        @Override
+        public void putDocuments(String packageName, String databaseName,
+                List<Bundle> documentBundles, int userId, IAppSearchBatchResultCallback callback)
+                throws RemoteException {
+            ignore(callback);
+        }
+
+        @Override
+        public void getDocuments(String packageName, String databaseName, String namespace,
+                List<String> uris, Map<String, List<String>> typePropertyPaths, int userId,
+                IAppSearchBatchResultCallback callback) throws RemoteException {
+            ignore(callback);
+        }
+
+        @Override
+        public void query(String packageName, String databaseName, String queryExpression,
+                Bundle searchSpecBundle, int userId, IAppSearchResultCallback callback)
+                throws RemoteException {
+            ignore(callback);
+        }
+
+        @Override
+        public void globalQuery(String packageName, String queryExpression, Bundle searchSpecBundle,
+                int userId, IAppSearchResultCallback callback) throws RemoteException {
+            ignore(callback);
+        }
+
+        @Override
+        public void getNextPage(long nextPageToken, int userId, IAppSearchResultCallback callback)
+                throws RemoteException {
+            ignore(callback);
+        }
+
+        @Override
+        public void invalidateNextPageToken(long nextPageToken, int userId) throws RemoteException {
+
+        }
+
+        @Override
+        public void reportUsage(String packageName, String databaseName, String namespace,
+                String uri, long usageTimeMillis, int userId, IAppSearchResultCallback callback)
+                throws RemoteException {
+            ignore(callback);
+        }
+
+        @Override
+        public void removeByUri(String packageName, String databaseName, String namespace,
+                List<String> uris, int userId, IAppSearchBatchResultCallback callback)
+                throws RemoteException {
+            ignore(callback);
+        }
+
+        @Override
+        public void removeByQuery(String packageName, String databaseName, String queryExpression,
+                Bundle searchSpecBundle, int userId, IAppSearchResultCallback callback)
+                throws RemoteException {
+            ignore(callback);
+        }
+
+        @Override
+        public void persistToDisk(int userId) throws RemoteException {
+
+        }
+
+        @Override
+        public void initialize(int userId, IAppSearchResultCallback callback)
+                throws RemoteException {
+            ignore(callback);
+        }
+
+        @Override
+        public IBinder asBinder() {
+            return null;
+        }
+
+        private void ignore(IAppSearchResultCallback callback) throws RemoteException {
+            callback.onResult(AppSearchResult.newSuccessfulResult(null));
+        }
+
+        private void ignore(IAppSearchBatchResultCallback callback) throws RemoteException {
+            callback.onResult(new AppSearchBatchResult.Builder().build());
+        }
+    }
+
     public static class ShortcutActivity extends Activity {
     }
 
@@ -652,6 +784,7 @@
     protected PackageManagerInternal mMockPackageManagerInternal;
     protected UserManager mMockUserManager;
     protected DevicePolicyManager mMockDevicePolicyManager;
+    protected MockAppSearchManager mMockAppSearchManager;
     protected UserManagerInternal mMockUserManagerInternal;
     protected UsageStatsManagerInternal mMockUsageStatsManagerInternal;
     protected ActivityManagerInternal mMockActivityManagerInternal;
@@ -801,6 +934,7 @@
         mMockPackageManagerInternal = mock(PackageManagerInternal.class);
         mMockUserManager = mock(UserManager.class);
         mMockDevicePolicyManager = mock(DevicePolicyManager.class);
+        mMockAppSearchManager = new MockAppSearchManager();
         mMockUserManagerInternal = mock(UserManagerInternal.class);
         mMockUsageStatsManagerInternal = mock(UsageStatsManagerInternal.class);
         mMockActivityManagerInternal = mock(ActivityManagerInternal.class);
diff --git a/services/tests/servicestests/src/com/android/server/pm/OWNERS b/services/tests/servicestests/src/com/android/server/pm/OWNERS
index d825dfd..e15b5f5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/OWNERS
+++ b/services/tests/servicestests/src/com/android/server/pm/OWNERS
@@ -1 +1,3 @@
 include /services/core/java/com/android/server/pm/OWNERS
+
+per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest12.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest12.java
new file mode 100644
index 0000000..b17085e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest12.java
@@ -0,0 +1,44 @@
+/*
+ * 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.pm;
+
+import android.app.appsearch.PackageIdentifier;
+import android.content.pm.AppSearchShortcutInfo;
+
+import java.util.Random;
+
+/**
+ * Tests for {@link android.app.appsearch.AppSearchManager} and relevant APIs in ShortcutManager.
+ *
+ atest -c com.android.server.pm.ShortcutManagerTest12
+ */
+public class ShortcutManagerTest12 extends BaseShortcutManagerTest {
+
+    public void testUpdateShortcutVisibility_updatesShortcutSchema() {
+
+        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)));
+        });
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
index fb13d87..c2b3858 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
@@ -17,10 +17,10 @@
 package com.android.server.pm.parsing;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
 import android.apex.ApexInfo;
 import android.content.Context;
@@ -39,6 +39,7 @@
 import android.os.Bundle;
 import android.os.FileUtils;
 import android.platform.test.annotations.Presubmit;
+import android.util.Pair;
 import android.util.SparseIntArray;
 
 import androidx.test.InstrumentationRegistry;
@@ -50,12 +51,17 @@
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
 
+import com.google.common.truth.Expect;
+
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.io.File;
 import java.io.InputStream;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.function.Function;
 
 /**
@@ -89,6 +95,8 @@
     private static final int PLATFORM_VERSION = 20;
     private static final int NEWER_VERSION = 30;
 
+    @Rule public final Expect expect = Expect.create();
+
     private void verifyComputeMinSdkVersion(int minSdkVersion, String minSdkCodename,
             boolean isPlatformReleased, int expectedMinSdk) {
         final String[] outError = new String[1];
@@ -553,36 +561,44 @@
 
     @Test
     public void testUsesSdk() throws Exception {
-        ParsedPackage pkg =
-                parsePackage("install_uses_sdk.apk_r0", R.raw.install_uses_sdk_r0, x -> x);
-        SparseIntArray minExtVers = pkg.getMinExtensionVersions();
+        ParsedPackage pkg;
+        SparseIntArray minExtVers;
+        pkg = parsePackage("install_uses_sdk.apk_r0", R.raw.install_uses_sdk_r0, x -> x);
+        minExtVers = pkg.getMinExtensionVersions();
         assertEquals(1, minExtVers.size());
-        assertEquals(0, minExtVers.get(10000, -1));
+        assertEquals(0, minExtVers.get(30, -1));
 
-        try {
-            parsePackage("install_uses_sdk.apk_r5", R.raw.install_uses_sdk_r5, x -> x);
-            fail("Expected parsing exception due to incompatible extension SDK version");
-        } catch (PackageParser.PackageParserException expected) {
-            assertEquals(PackageManager.INSTALL_FAILED_OLDER_SDK, expected.error);
-        }
-        try {
-            parsePackage("install_uses_sdk.apk_q0", R.raw.install_uses_sdk_q0, x -> x);
-            fail("Expected parsing exception due to non-existent extension SDK");
-        } catch (PackageParser.PackageParserException expected) {
-            assertEquals(PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, expected.error);
-        }
-        try {
-            parsePackage("install_uses_sdk.apk_r", R.raw.install_uses_sdk_r, x -> x);
-            fail("Expected parsing exception due to unspecified extension SDK version");
-        } catch (PackageParser.PackageParserException expected) {
-            assertEquals(PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, expected.error);
-        }
-        try {
-            parsePackage("install_uses_sdk.apk_0", R.raw.install_uses_sdk_0, x -> x);
-            fail("Expected parsing exception due to unspecified extension SDK");
-        } catch (PackageParser.PackageParserException expected) {
-            assertEquals(PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, expected.error);
-        }
+        pkg = parsePackage("install_uses_sdk.apk_r0_s0", R.raw.install_uses_sdk_r0_s0, x -> x);
+        minExtVers = pkg.getMinExtensionVersions();
+        assertEquals(2, minExtVers.size());
+        assertEquals(0, minExtVers.get(30, -1));
+        assertEquals(0, minExtVers.get(31, -1));
 
+        Map<Pair<String, Integer>, Integer> appToError = new HashMap<>();
+        appToError.put(Pair.create("install_uses_sdk.apk_r5", R.raw.install_uses_sdk_r5),
+                       PackageManager.INSTALL_FAILED_OLDER_SDK);
+        appToError.put(Pair.create("install_uses_sdk.apk_r0_s5", R.raw.install_uses_sdk_r0_s5),
+                       PackageManager.INSTALL_FAILED_OLDER_SDK);
+
+        appToError.put(Pair.create("install_uses_sdk.apk_q0", R.raw.install_uses_sdk_q0),
+                       PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED);
+        appToError.put(Pair.create("install_uses_sdk.apk_q0_r0", R.raw.install_uses_sdk_q0_r0),
+                       PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED);
+        appToError.put(Pair.create("install_uses_sdk.apk_r_none", R.raw.install_uses_sdk_r_none),
+                       PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED);
+        appToError.put(Pair.create("install_uses_sdk.apk_0", R.raw.install_uses_sdk_0),
+                       PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED);
+
+        for (Map.Entry<Pair<String, Integer>, Integer> entry : appToError.entrySet()) {
+            String filename = entry.getKey().first;
+            int resId = entry.getKey().second;
+            int result = entry.getValue();
+            try {
+                parsePackage(filename, resId, x -> x);
+                expect.withMessage("Expected parsing error %d from %s", result, filename).fail();
+            } catch (PackageParser.PackageParserException expected) {
+                expect.that(expected.error).isEqualTo(result);
+            }
+        }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
index ddbe81c..26b34fd 100644
--- a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
@@ -318,7 +318,8 @@
         assertTrue(pssProto.energyMeasurement.length == ENERGY_METER_COUNT);
         for (int i = 0; i < pssProto.energyMeasurement.length; i++) {
             assertTrue(pssProto.energyMeasurement[i].id == i);
-            assertTrue(pssProto.energyMeasurement[i].timestampMs == i);
+            assertTrue(pssProto.energyMeasurement[i].timestampMs ==
+                    i + mPowerStatsLogger.getStartWallTime());
             assertTrue(pssProto.energyMeasurement[i].durationMs == i);
             assertTrue(pssProto.energyMeasurement[i].energyUws == i);
         }
@@ -359,7 +360,8 @@
         assertTrue(pssProto.energyConsumerResult.length == ENERGY_CONSUMER_COUNT);
         for (int i = 0; i < pssProto.energyConsumerResult.length; i++) {
             assertTrue(pssProto.energyConsumerResult[i].id == i);
-            assertTrue(pssProto.energyConsumerResult[i].timestampMs == i);
+            assertTrue(pssProto.energyConsumerResult[i].timestampMs ==
+                    i + mPowerStatsLogger.getStartWallTime());
             assertTrue(pssProto.energyConsumerResult[i].energyUws == i);
             assertTrue(pssProto.energyConsumerResult[i].attribution.length
                     == ENERGY_CONSUMER_ATTRIBUTION_COUNT);
@@ -420,7 +422,8 @@
                 assertTrue(stateResidency.id == j);
                 assertTrue(stateResidency.totalTimeInStateMs == j);
                 assertTrue(stateResidency.totalStateEntryCount == j);
-                assertTrue(stateResidency.lastEntryTimestampMs == j);
+                assertTrue(stateResidency.lastEntryTimestampMs ==
+                        j + mPowerStatsLogger.getStartWallTime());
             }
         }
     }
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/OWNERS b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/OWNERS
index 816bc6b..33385af 100644
--- a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/OWNERS
+++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/OWNERS
@@ -1 +1 @@
-include /core/java/android/media/soundtrigger/OWNERS
+include /media/aidl/android/media/soundtrigger_middleware/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
index 682a80c..5d27552 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
@@ -46,8 +46,8 @@
     public void test_unrestricted() {
         ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
                 .setUserConfigAllowed(true)
-                .setAutoDetectionSupported(true)
-                .setGeoDetectionSupported(true)
+                .setAutoDetectionFeatureSupported(true)
+                .setGeoDetectionFeatureSupported(true)
                 .setAutoDetectionEnabled(true)
                 .setLocationEnabled(true)
                 .setGeoDetectionEnabled(true)
@@ -108,8 +108,8 @@
     public void test_restricted() {
         ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
                 .setUserConfigAllowed(false)
-                .setAutoDetectionSupported(true)
-                .setGeoDetectionSupported(true)
+                .setAutoDetectionFeatureSupported(true)
+                .setGeoDetectionFeatureSupported(true)
                 .setAutoDetectionEnabled(true)
                 .setLocationEnabled(true)
                 .setGeoDetectionEnabled(true)
@@ -170,8 +170,8 @@
     public void test_autoDetectNotSupported() {
         ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
                 .setUserConfigAllowed(true)
-                .setAutoDetectionSupported(false)
-                .setGeoDetectionSupported(false)
+                .setAutoDetectionFeatureSupported(false)
+                .setGeoDetectionFeatureSupported(false)
                 .setAutoDetectionEnabled(true)
                 .setLocationEnabled(true)
                 .setGeoDetectionEnabled(true)
@@ -232,8 +232,8 @@
     public void test_geoDetectNotSupported() {
         ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
                 .setUserConfigAllowed(true)
-                .setAutoDetectionSupported(true)
-                .setGeoDetectionSupported(false)
+                .setAutoDetectionFeatureSupported(true)
+                .setGeoDetectionFeatureSupported(false)
                 .setAutoDetectionEnabled(true)
                 .setLocationEnabled(true)
                 .setGeoDetectionEnabled(true)
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
index d2452ea..14e0bbd 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
@@ -364,8 +364,8 @@
         // the tests.
         final boolean geoDetectionEnabled = autoDetectionEnabled;
         return new ConfigurationInternal.Builder(ARBITRARY_USER_ID)
-                .setAutoDetectionSupported(true)
-                .setGeoDetectionSupported(true)
+                .setAutoDetectionFeatureSupported(true)
+                .setGeoDetectionFeatureSupported(true)
                 .setUserConfigAllowed(true)
                 .setAutoDetectionEnabled(autoDetectionEnabled)
                 .setLocationEnabled(geoDetectionEnabled)
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
index c8dba5f..f1f8b2f 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
@@ -90,8 +90,8 @@
     private static final ConfigurationInternal CONFIG_INT_USER_RESTRICTED_AUTO_DISABLED =
             new ConfigurationInternal.Builder(USER_ID)
                     .setUserConfigAllowed(false)
-                    .setAutoDetectionSupported(true)
-                    .setGeoDetectionSupported(true)
+                    .setAutoDetectionFeatureSupported(true)
+                    .setGeoDetectionFeatureSupported(true)
                     .setAutoDetectionEnabled(false)
                     .setLocationEnabled(true)
                     .setGeoDetectionEnabled(false)
@@ -100,8 +100,8 @@
     private static final ConfigurationInternal CONFIG_INT_USER_RESTRICTED_AUTO_ENABLED =
             new ConfigurationInternal.Builder(USER_ID)
                     .setUserConfigAllowed(false)
-                    .setAutoDetectionSupported(true)
-                    .setGeoDetectionSupported(true)
+                    .setAutoDetectionFeatureSupported(true)
+                    .setGeoDetectionFeatureSupported(true)
                     .setAutoDetectionEnabled(true)
                     .setLocationEnabled(true)
                     .setGeoDetectionEnabled(true)
@@ -110,8 +110,8 @@
     private static final ConfigurationInternal CONFIG_INT_AUTO_DETECT_NOT_SUPPORTED =
             new ConfigurationInternal.Builder(USER_ID)
                     .setUserConfigAllowed(true)
-                    .setAutoDetectionSupported(false)
-                    .setGeoDetectionSupported(false)
+                    .setAutoDetectionFeatureSupported(false)
+                    .setGeoDetectionFeatureSupported(false)
                     .setAutoDetectionEnabled(false)
                     .setLocationEnabled(true)
                     .setGeoDetectionEnabled(false)
@@ -120,8 +120,8 @@
     private static final ConfigurationInternal CONFIG_INT_AUTO_SUPPORTED_GEO_NOT_SUPPORTED =
             new ConfigurationInternal.Builder(USER_ID)
                     .setUserConfigAllowed(true)
-                    .setAutoDetectionSupported(true)
-                    .setGeoDetectionSupported(false)
+                    .setAutoDetectionFeatureSupported(true)
+                    .setGeoDetectionFeatureSupported(false)
                     .setAutoDetectionEnabled(true)
                     .setLocationEnabled(true)
                     .setGeoDetectionEnabled(true)
@@ -130,8 +130,8 @@
     private static final ConfigurationInternal CONFIG_INT_AUTO_DISABLED_GEO_DISABLED =
             new ConfigurationInternal.Builder(USER_ID)
                     .setUserConfigAllowed(true)
-                    .setAutoDetectionSupported(true)
-                    .setGeoDetectionSupported(true)
+                    .setAutoDetectionFeatureSupported(true)
+                    .setGeoDetectionFeatureSupported(true)
                     .setAutoDetectionEnabled(false)
                     .setLocationEnabled(true)
                     .setGeoDetectionEnabled(false)
@@ -139,8 +139,8 @@
 
     private static final ConfigurationInternal CONFIG_INT_AUTO_ENABLED_GEO_DISABLED =
             new ConfigurationInternal.Builder(USER_ID)
-                    .setAutoDetectionSupported(true)
-                    .setGeoDetectionSupported(true)
+                    .setAutoDetectionFeatureSupported(true)
+                    .setGeoDetectionFeatureSupported(true)
                     .setUserConfigAllowed(true)
                     .setAutoDetectionEnabled(true)
                     .setLocationEnabled(true)
@@ -149,8 +149,8 @@
 
     private static final ConfigurationInternal CONFIG_INT_AUTO_ENABLED_GEO_ENABLED =
             new ConfigurationInternal.Builder(USER_ID)
-                    .setAutoDetectionSupported(true)
-                    .setGeoDetectionSupported(true)
+                    .setAutoDetectionFeatureSupported(true)
+                    .setGeoDetectionFeatureSupported(true)
                     .setUserConfigAllowed(true)
                     .setAutoDetectionEnabled(true)
                     .setLocationEnabled(true)
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java
index d319488..8280cdc 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java
@@ -44,8 +44,8 @@
             @UserIdInt int userId, boolean geoDetectionEnabled) {
         return new ConfigurationInternal.Builder(userId)
                 .setUserConfigAllowed(true)
-                .setAutoDetectionSupported(true)
-                .setGeoDetectionSupported(true)
+                .setAutoDetectionFeatureSupported(true)
+                .setGeoDetectionFeatureSupported(true)
                 .setAutoDetectionEnabled(true)
                 .setLocationEnabled(true)
                 .setGeoDetectionEnabled(geoDetectionEnabled)
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 11fb002..624c3de 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -144,6 +144,9 @@
     private static final long RARE_THRESHOLD = 48 * HOUR_MS;
     private static final long RESTRICTED_THRESHOLD = 96 * HOUR_MS;
 
+    private static final int ASSERT_RETRY_ATTEMPTS = 20;
+    private static final int ASSERT_RETRY_DELAY_MILLISECONDS = 500;
+
     /** Mock variable used in {@link MyInjector#isPackageInstalled(String, int, int)} */
     private static boolean isPackageInstalled = true;
 
@@ -589,16 +592,37 @@
                 mInjector.mElapsedRealtime);
     }
 
-    private void assertBucket(int bucket) {
+    private void assertBucket(int bucket) throws InterruptedException {
         assertBucket(bucket, PACKAGE_1);
     }
 
-    private void assertBucket(int bucket, String pkg) {
+    private void assertBucket(int bucket, String pkg) throws InterruptedException {
+        int retries = 0;
+        do {
+            if (bucket == getStandbyBucket(mController, pkg)) {
+                // Success
+                return;
+            }
+            Thread.sleep(ASSERT_RETRY_DELAY_MILLISECONDS);
+            retries++;
+        } while(retries < ASSERT_RETRY_ATTEMPTS);
+        // try one last time
         assertEquals(bucket, getStandbyBucket(mController, pkg));
     }
 
-    private void assertNotBucket(int bucket) {
-        assertNotEquals(bucket, getStandbyBucket(mController, PACKAGE_1));
+    private void assertNotBucket(int bucket) throws InterruptedException {
+        final String pkg = PACKAGE_1;
+        int retries = 0;
+        do {
+            if (bucket != getStandbyBucket(mController, pkg)) {
+                // Success
+                return;
+            }
+            Thread.sleep(ASSERT_RETRY_DELAY_MILLISECONDS);
+            retries++;
+        } while(retries < ASSERT_RETRY_ATTEMPTS);
+        // try one last time
+        assertNotEquals(bucket, getStandbyBucket(mController, pkg));
     }
 
     @Test
@@ -996,7 +1020,7 @@
      * a low bucket after the RESTRICTED timeout.
      */
     @Test
-    public void testRestrictedTimeoutOverridesRestoredLowBucketPrediction() {
+    public void testRestrictedTimeoutOverridesRestoredLowBucketPrediction() throws Exception {
         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
         assertBucket(STANDBY_BUCKET_ACTIVE);
 
@@ -1032,7 +1056,7 @@
      * a low bucket after the RESTRICTED timeout.
      */
     @Test
-    public void testRestrictedTimeoutOverridesPredictionLowBucket() {
+    public void testRestrictedTimeoutOverridesPredictionLowBucket() throws Exception {
         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
 
         // Not long enough to time out into RESTRICTED.
@@ -1055,7 +1079,7 @@
     }
 
     @Test
-    public void testRestrictedBucketDisabled() {
+    public void testRestrictedBucketDisabled() throws Exception {
         mInjector.mIsRestrictedBucketEnabled = false;
         // Get the controller to read the new value. Capturing the ContentObserver isn't possible
         // at the moment.
@@ -1080,7 +1104,7 @@
     }
 
     @Test
-    public void testRestrictedBucket_EnabledToDisabled() {
+    public void testRestrictedBucket_EnabledToDisabled() throws Exception {
         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
         mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD;
         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
@@ -1097,7 +1121,7 @@
     }
 
     @Test
-    public void testPredictionRaiseFromRestrictedTimeout_highBucket() {
+    public void testPredictionRaiseFromRestrictedTimeout_highBucket() throws Exception {
         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
 
         // Way past all timeouts. App times out into RESTRICTED bucket.
@@ -1114,7 +1138,7 @@
     }
 
     @Test
-    public void testPredictionRaiseFromRestrictedTimeout_lowBucket() {
+    public void testPredictionRaiseFromRestrictedTimeout_lowBucket() throws Exception {
         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
 
         // Way past all timeouts. App times out into RESTRICTED bucket.
@@ -1366,7 +1390,7 @@
     }
 
     @Test
-    public void testAddActiveDeviceAdmin() {
+    public void testAddActiveDeviceAdmin() throws Exception {
         assertActiveAdmins(USER_ID, (String[]) null);
         assertActiveAdmins(USER_ID2, (String[]) null);
 
@@ -1402,7 +1426,7 @@
     }
 
     @Test
-    public void isActiveDeviceAdmin() {
+    public void isActiveDeviceAdmin() throws Exception {
         assertActiveAdmins(USER_ID, (String[]) null);
         assertActiveAdmins(USER_ID2, (String[]) null);
 
@@ -1488,7 +1512,7 @@
     }
 
     @Test
-    public void testAppUpdateOnRestrictedBucketStatus() {
+    public void testAppUpdateOnRestrictedBucketStatus() throws Exception {
         // Updates shouldn't change bucket if the app timed out.
         // Way past all timeouts. App times out into RESTRICTED bucket.
         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
@@ -1563,7 +1587,7 @@
     }
 
     @Test
-    public void testSystemHeadlessAppElevated() {
+    public void testSystemHeadlessAppElevated() throws Exception {
         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime,
                 PACKAGE_SYSTEM_HEADFULL);
@@ -1589,7 +1613,7 @@
     }
 
     @Test
-    public void testWellbeingAppElevated() {
+    public void testWellbeingAppElevated() throws Exception {
         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_WELLBEING);
         assertBucket(STANDBY_BUCKET_ACTIVE, PACKAGE_WELLBEING);
         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
index 8c62b7f..3ca9060 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
@@ -91,6 +91,7 @@
 
         mInputDeviceDelegate = new InputDeviceDelegate(
                 mContextSpy, new Handler(mTestLooper.getLooper()));
+        mInputDeviceDelegate.onSystemReady();
     }
 
     @After
@@ -99,6 +100,24 @@
     }
 
     @Test
+    public void beforeSystemReady_ignoresAnyUpdate() throws Exception {
+        when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[0]);
+        InputDeviceDelegate inputDeviceDelegate = new InputDeviceDelegate(
+                mContextSpy, new Handler(mTestLooper.getLooper()));
+
+        inputDeviceDelegate.updateInputDeviceVibrators(/* vibrateInputDevices= */ true);
+        assertFalse(inputDeviceDelegate.isAvailable());
+
+        inputDeviceDelegate.onInputDeviceAdded(1);
+        assertFalse(inputDeviceDelegate.isAvailable());
+
+        updateInputDevices(new int[]{1});
+        assertFalse(inputDeviceDelegate.isAvailable());
+
+        verify(mIInputManagerMock, never()).getInputDevice(anyInt());
+    }
+
+    @Test
     public void onInputDeviceAdded_withSettingsDisabled_ignoresNewDevice() throws Exception {
         when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[0]);
         mInputDeviceDelegate.updateInputDeviceVibrators(/* vibrateInputDevices= */ false);
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java
index 1e6ef91..b6c11fe 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java
@@ -88,6 +88,7 @@
         mVibrationSettings = new VibrationSettings(
                 mContextSpy, new Handler(mTestLooper.getLooper()));
         mVibrationScaler = new VibrationScaler(mContextSpy, mVibrationSettings);
+        mVibrationSettings.onSystemReady();
     }
 
     @After
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
index d867987..85501245 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
@@ -106,6 +106,7 @@
         mAudioManager = mContextSpy.getSystemService(AudioManager.class);
         mVibrationSettings = new VibrationSettings(mContextSpy,
                 new Handler(mTestLooper.getLooper()));
+        mVibrationSettings.onSystemReady();
 
         setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0);
         setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
@@ -162,6 +163,23 @@
     }
 
     @Test
+    public void shouldVibrateForRingerMode_beforeSystemReady_returnsFalseOnlyForRingtone() {
+        setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
+        setRingerMode(AudioManager.RINGER_MODE_MAX);
+        VibrationSettings vibrationSettings = new VibrationSettings(mContextSpy,
+                new Handler(mTestLooper.getLooper()));
+
+        assertFalse(vibrationSettings.shouldVibrateForRingerMode(
+                VibrationAttributes.USAGE_RINGTONE));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(VibrationAttributes.USAGE_ALARM));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(VibrationAttributes.USAGE_TOUCH));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(
+                VibrationAttributes.USAGE_NOTIFICATION));
+        assertTrue(mVibrationSettings.shouldVibrateForRingerMode(
+                VibrationAttributes.USAGE_COMMUNICATION_REQUEST));
+    }
+
+    @Test
     public void shouldVibrateForRingerMode_withoutRingtoneUsage_returnsTrue() {
         assertTrue(mVibrationSettings.shouldVibrateForRingerMode(VibrationAttributes.USAGE_ALARM));
         assertTrue(mVibrationSettings.shouldVibrateForRingerMode(VibrationAttributes.USAGE_TOUCH));
@@ -303,6 +321,37 @@
     }
 
     @Test
+    public void getDefaultIntensity_beforeSystemReady_returnsMediumToAllExceptAlarm() {
+        mFakeVibrator.setDefaultHapticFeedbackIntensity(Vibrator.VIBRATION_INTENSITY_HIGH);
+        mFakeVibrator.setDefaultNotificationVibrationIntensity(Vibrator.VIBRATION_INTENSITY_HIGH);
+        mFakeVibrator.setDefaultRingVibrationIntensity(Vibrator.VIBRATION_INTENSITY_HIGH);
+
+        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_OFF);
+        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_OFF);
+        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_OFF);
+
+        VibrationSettings vibrationSettings = new VibrationSettings(mContextSpy,
+                new Handler(mTestLooper.getLooper()));
+
+        assertEquals(Vibrator.VIBRATION_INTENSITY_HIGH,
+                vibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_ALARM));
+        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
+                vibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_TOUCH));
+        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
+                vibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_NOTIFICATION));
+        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
+                vibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_UNKNOWN));
+        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
+                vibrationSettings.getDefaultIntensity(
+                        VibrationAttributes.USAGE_PHYSICAL_EMULATION));
+        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
+                vibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_RINGTONE));
+    }
+
+    @Test
     public void getDefaultIntensity_returnsIntensityFromVibratorService() {
         mFakeVibrator.setDefaultHapticFeedbackIntensity(Vibrator.VIBRATION_INTENSITY_HIGH);
         mFakeVibrator.setDefaultNotificationVibrationIntensity(Vibrator.VIBRATION_INTENSITY_MEDIUM);
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index ba0a472..a28d18f 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -176,8 +176,14 @@
         LocalServices.removeServiceForTest(PowerManagerInternal.class);
     }
 
+    private VibratorManagerService createSystemReadyService() {
+        VibratorManagerService service = createService();
+        service.systemReady();
+        return service;
+    }
+
     private VibratorManagerService createService() {
-        VibratorManagerService service = new VibratorManagerService(
+        return new VibratorManagerService(
                 mContextSpy,
                 new VibratorManagerService.Injector() {
                     @Override
@@ -201,8 +207,6 @@
                     void addService(String name, IBinder service) {
                     }
                 });
-        service.systemReady();
-        return service;
     }
 
     @Test
@@ -215,21 +219,44 @@
     }
 
     @Test
+    public void createService_doNotCrashIfUsedBeforeSystemReady() {
+        mockVibrators(1, 2);
+        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
+        mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
+        VibratorManagerService service = createService();
+
+        assertNotNull(service.getVibratorIds());
+        assertNotNull(service.getVibratorInfo(1));
+        assertFalse(service.isVibrating(1));
+
+        CombinedVibrationEffect effect = CombinedVibrationEffect.createSynced(
+                VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
+        vibrate(service, effect, HAPTIC_FEEDBACK_ATTRS);
+        service.cancelVibrate(service);
+
+        assertTrue(service.setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
+
+        IVibratorStateListener listener = mockVibratorStateListener();
+        assertTrue(service.registerVibratorStateListener(1, listener));
+        assertTrue(service.unregisterVibratorStateListener(1, listener));
+    }
+
+    @Test
     public void getVibratorIds_withNullResultFromNative_returnsEmptyArray() {
         when(mNativeWrapperMock.getVibratorIds()).thenReturn(null);
-        assertArrayEquals(new int[0], createService().getVibratorIds());
+        assertArrayEquals(new int[0], createSystemReadyService().getVibratorIds());
     }
 
     @Test
     public void getVibratorIds_withNonEmptyResultFromNative_returnsSameArray() {
         mockVibrators(2, 1);
-        assertArrayEquals(new int[]{2, 1}, createService().getVibratorIds());
+        assertArrayEquals(new int[]{2, 1}, createSystemReadyService().getVibratorIds());
     }
 
     @Test
     public void getVibratorInfo_withMissingVibratorId_returnsNull() {
         mockVibrators(1);
-        assertNull(createService().getVibratorInfo(2));
+        assertNull(createSystemReadyService().getVibratorInfo(2));
     }
 
     @Test
@@ -239,7 +266,7 @@
         vibrator.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS, IVibrator.CAP_AMPLITUDE_CONTROL);
         vibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
         vibrator.setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK);
-        VibratorInfo info = createService().getVibratorInfo(1);
+        VibratorInfo info = createSystemReadyService().getVibratorInfo(1);
 
         assertNotNull(info);
         assertEquals(1, info.getId());
@@ -257,7 +284,7 @@
     @Test
     public void registerVibratorStateListener_callbacksAreTriggered() throws Exception {
         mockVibrators(1);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
         IVibratorStateListener listenerMock = mockVibratorStateListener();
         service.registerVibratorStateListener(1, listenerMock);
 
@@ -278,7 +305,7 @@
     @Test
     public void unregisterVibratorStateListener_callbackNotTriggeredAfter() throws Exception {
         mockVibrators(1);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
         IVibratorStateListener listenerMock = mockVibratorStateListener();
         service.registerVibratorStateListener(1, listenerMock);
 
@@ -303,7 +330,7 @@
     @Test
     public void registerVibratorStateListener_multipleVibratorsAreTriggered() throws Exception {
         mockVibrators(0, 1, 2);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
         IVibratorStateListener[] listeners = new IVibratorStateListener[3];
         for (int i = 0; i < 3; i++) {
             listeners[i] = mockVibratorStateListener();
@@ -330,7 +357,8 @@
 
         CombinedVibrationEffect effect = CombinedVibrationEffect.createSynced(
                 VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
-        assertTrue(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
+        assertTrue(createSystemReadyService().setAlwaysOnEffect(
+                UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
 
         VibrationEffect.Prebaked expectedEffect = new VibrationEffect.Prebaked(
                 VibrationEffect.EFFECT_CLICK, false, VibrationEffect.EFFECT_STRENGTH_STRONG);
@@ -353,7 +381,8 @@
                 .addVibrator(2, VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK))
                 .addVibrator(3, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK))
                 .combine();
-        assertTrue(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
+        assertTrue(createSystemReadyService().setAlwaysOnEffect(
+                UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
 
         VibrationEffect.Prebaked expectedClick = new VibrationEffect.Prebaked(
                 VibrationEffect.EFFECT_CLICK, false, VibrationEffect.EFFECT_STRENGTH_STRONG);
@@ -376,9 +405,11 @@
 
         CombinedVibrationEffect effect = CombinedVibrationEffect.createSynced(
                 VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
-        assertTrue(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
+        assertTrue(createSystemReadyService().setAlwaysOnEffect(
+                UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
 
-        assertTrue(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, null, ALARM_ATTRS));
+        assertTrue(createSystemReadyService().setAlwaysOnEffect(
+                UID, PACKAGE_NAME, 1, null, ALARM_ATTRS));
 
         assertNull(mVibratorProviders.get(1).getAlwaysOnEffect(1));
         assertNull(mVibratorProviders.get(2).getAlwaysOnEffect(1));
@@ -392,7 +423,8 @@
 
         CombinedVibrationEffect effect = CombinedVibrationEffect.createSynced(
                 VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE));
-        assertFalse(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
+        assertFalse(createSystemReadyService().setAlwaysOnEffect(
+                UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
 
         assertNull(mVibratorProviders.get(1).getAlwaysOnEffect(1));
     }
@@ -405,7 +437,8 @@
         CombinedVibrationEffect effect = CombinedVibrationEffect.startSequential()
                 .addNext(0, VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
                 .combine();
-        assertFalse(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
+        assertFalse(createSystemReadyService().setAlwaysOnEffect(
+                UID, PACKAGE_NAME, 1, effect, ALARM_ATTRS));
 
         assertNull(mVibratorProviders.get(1).getAlwaysOnEffect(1));
     }
@@ -413,7 +446,7 @@
     @Test
     public void setAlwaysOnEffect_withNoVibratorWithCapability_ignoresEffect() {
         mockVibrators(1);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
 
         CombinedVibrationEffect mono = CombinedVibrationEffect.createSynced(
                 VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
@@ -435,18 +468,18 @@
         setRingerMode(AudioManager.RINGER_MODE_NORMAL);
         setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
         setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
         vibrate(service, VibrationEffect.createOneShot(40, 1), RINGTONE_ATTRS);
 
         setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
         setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 1);
-        service = createService();
+        service = createSystemReadyService();
         vibrate(service, VibrationEffect.createOneShot(40, 10), RINGTONE_ATTRS);
         assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
 
         setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
         setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0);
-        service = createService();
+        service = createSystemReadyService();
         vibrate(service, VibrationEffect.createOneShot(40, 100), RINGTONE_ATTRS);
         assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
 
@@ -459,7 +492,7 @@
         mockVibrators(1);
         FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
         fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
         mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
         vibrate(service, VibrationEffect.createOneShot(1, 1), HAPTIC_FEEDBACK_ATTRS);
         vibrate(service, VibrationEffect.createOneShot(2, 2), RINGTONE_ATTRS);
@@ -480,7 +513,7 @@
 
     @Test
     public void vibrate_withAudioAttributes_usesOriginalAudioUsageInAppOpsManager() {
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
 
         VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
         AudioAttributes audioAttributes = new AudioAttributes.Builder()
@@ -496,7 +529,7 @@
 
     @Test
     public void vibrate_withVibrationAttributes_usesCorrespondingAudioUsageInAppOpsManager() {
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
 
         vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), ALARM_ATTRS);
         vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_TICK), NOTIFICATION_ATTRS);
@@ -534,7 +567,7 @@
         when(mIInputManagerMock.getVibratorIds(eq(1))).thenReturn(new int[]{1});
         when(mIInputManagerMock.getInputDevice(eq(1))).thenReturn(createInputDeviceWithVibrator(1));
         setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
 
         CombinedVibrationEffect effect = CombinedVibrationEffect.createSynced(
                 VibrationEffect.createOneShot(10, 10));
@@ -550,7 +583,7 @@
     public void vibrate_withNativeCallbackTriggered_finishesVibration() throws Exception {
         mockVibrators(1);
         mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
         // The native callback will be dispatched manually in this test.
         mTestLooper.stopAutoDispatchAndIgnoreExceptions();
 
@@ -573,7 +606,7 @@
         mockVibrators(1, 2);
         mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
         mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
         // The native callback will be dispatched manually in this test.
         mTestLooper.stopAutoDispatchAndIgnoreExceptions();
 
@@ -619,7 +652,7 @@
         FakeVibratorControllerProvider fakeVibrator1 = mVibratorProviders.get(1);
         fakeVibrator1.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
         mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
 
         CombinedVibrationEffect effect = CombinedVibrationEffect.startSynced()
                 .addVibrator(1, VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
@@ -645,7 +678,7 @@
         mockVibrators(1, 2);
         FakeVibratorControllerProvider fakeVibrator1 = mVibratorProviders.get(1);
         fakeVibrator1.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
 
         CombinedVibrationEffect effect = CombinedVibrationEffect.startSynced()
                 .addVibrator(1, VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
@@ -665,7 +698,7 @@
         mockCapabilities(IVibratorManager.CAP_SYNC, IVibratorManager.CAP_PREPARE_ON);
         mockVibrators(1, 2);
         when(mNativeWrapperMock.prepareSynced(any())).thenReturn(false);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
 
         CombinedVibrationEffect effect = CombinedVibrationEffect.startSynced()
                 .addVibrator(1, VibrationEffect.createOneShot(10, 50))
@@ -686,7 +719,7 @@
         mockVibrators(1, 2);
         when(mNativeWrapperMock.prepareSynced(eq(new int[]{1, 2}))).thenReturn(true);
         when(mNativeWrapperMock.triggerSynced(anyLong())).thenReturn(false);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
 
         CombinedVibrationEffect effect = CombinedVibrationEffect.startSynced()
                 .addVibrator(1, VibrationEffect.createOneShot(10, 50))
@@ -716,7 +749,7 @@
         fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL,
                 IVibrator.CAP_COMPOSE_EFFECTS);
         fakeVibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
 
         vibrate(service, CombinedVibrationEffect.startSynced()
                 .addVibrator(1, VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
@@ -762,7 +795,7 @@
     @Test
     public void vibrate_withPowerModeChange_cancelVibrationIfNotAllowed() throws Exception {
         mockVibrators(1, 2);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
         vibrate(service,
                 CombinedVibrationEffect.startSynced()
                         .addVibrator(1, VibrationEffect.createOneShot(1000, 100))
@@ -780,7 +813,7 @@
     @Test
     public void vibrate_withSettingsChange_doNotCancelVibration() throws Exception {
         mockVibrators(1);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
 
         vibrate(service, VibrationEffect.createOneShot(1000, 100), HAPTIC_FEEDBACK_ATTRS);
         assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
@@ -793,7 +826,7 @@
     @Test
     public void cancelVibrate_stopsVibrating() throws Exception {
         mockVibrators(1);
-        VibratorManagerService service = createService();
+        VibratorManagerService service = createSystemReadyService();
 
         service.cancelVibrate(service);
         assertFalse(service.isVibrating(1));
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
index 80a046a..9ac755f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
@@ -17,6 +17,8 @@
 
 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT;
 
 import static com.android.server.notification.NotificationManagerService.NotificationListeners.TAG_REQUESTED_LISTENERS;
 
@@ -205,6 +207,52 @@
     }
 
     @Test
+    public void testEnsureFilters_newServiceWithMetadata_onlyOneListed() {
+        ServiceInfo si = new ServiceInfo();
+        si.packageName = "new";
+        si.name = "comp";
+        si.metaData = new Bundle();
+        si.metaData.putInt(NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES, 2);
+
+        mListeners.ensureFilters(si, 0);
+
+        assertThat(mListeners.getNotificationListenerFilter(
+                Pair.create(si.getComponentName(), 0)).getTypes())
+                .isEqualTo(FLAG_FILTER_TYPE_ALERTING);
+    }
+
+    @Test
+    public void testEnsureFilters_newServiceWithMetadata_disabledTypes() {
+        ServiceInfo si = new ServiceInfo();
+        si.packageName = "new";
+        si.name = "comp";
+        si.metaData = new Bundle();
+        si.metaData.putString(NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES, "1,2");
+
+        mListeners.ensureFilters(si, 0);
+
+        assertThat(mListeners.getNotificationListenerFilter(
+                Pair.create(si.getComponentName(), 0)).getTypes())
+                .isEqualTo(FLAG_FILTER_TYPE_SILENT | FLAG_FILTER_TYPE_ONGOING);
+    }
+
+    @Test
+    public void testEnsureFilters_newServiceWithMetadata_metaDataDisagrees() {
+        ServiceInfo si = new ServiceInfo();
+        si.packageName = "new";
+        si.name = "comp";
+        si.metaData = new Bundle();
+        si.metaData.putString(NotificationListenerService.META_DATA_DEFAULT_FILTER_TYPES, "1,2");
+        si.metaData.putInt(NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES, 1);
+
+        mListeners.ensureFilters(si, 0);
+
+        assertThat(mListeners.getNotificationListenerFilter(
+                Pair.create(si.getComponentName(), 0)).getTypes())
+                .isEqualTo(FLAG_FILTER_TYPE_ALERTING);
+    }
+
+    @Test
     public void testEnsureFilters_newServiceWithEmptyMetadata() {
         ServiceInfo si = new ServiceInfo();
         si.packageName = "new";
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index a640509..cebdbbe 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -3671,8 +3671,8 @@
         mService.addNotification(r);
 
         final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 0, 1, true);
-        mService.mNotificationDelegate.onNotificationClear(mUid, 0, PKG, r.getSbn().getTag(),
-                r.getSbn().getId(), r.getUserId(), r.getKey(), NotificationStats.DISMISSAL_AOD,
+        mService.mNotificationDelegate.onNotificationClear(mUid, 0, PKG, r.getUserId(),
+                r.getKey(), NotificationStats.DISMISSAL_AOD,
                 NotificationStats.DISMISS_SENTIMENT_POSITIVE, nv);
         waitForIdle();
 
@@ -3694,8 +3694,8 @@
         mService.addNotification(r);
 
         final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 0, 1, true);
-        mService.mNotificationDelegate.onNotificationClear(mUid, 0, PKG, r.getSbn().getTag(),
-                r.getSbn().getId(), r.getUserId(), r.getKey(), NotificationStats.DISMISSAL_AOD,
+        mService.mNotificationDelegate.onNotificationClear(mUid, 0, PKG, r.getUserId(),
+                r.getKey(), NotificationStats.DISMISSAL_AOD,
                 NotificationStats.DISMISS_SENTIMENT_NEGATIVE, nv);
         waitForIdle();
 
@@ -6693,8 +6693,7 @@
         final NotificationVisibility nv = NotificationVisibility.obtain(nrSummary.getKey(), 1, 2,
                 true);
         mService.mNotificationDelegate.onNotificationClear(mUid, 0, PKG,
-                nrSummary.getSbn().getTag(),
-                nrSummary.getSbn().getId(), nrSummary.getUserId(), nrSummary.getKey(),
+                nrSummary.getUserId(), nrSummary.getKey(),
                 NotificationStats.DISMISSAL_SHADE,
                 NotificationStats.DISMISS_SENTIMENT_NEUTRAL, nv);
         waitForIdle();
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 488e629..d8e7582 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -555,9 +555,10 @@
         activity.setRequestedOrientation(
                 isScreenPortrait ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE);
 
-        // Asserts it has orientation derived from bounds.
-        assertEquals(isScreenPortrait ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT,
+        // Asserts it has orientation derived requested orientation (fixed orientation letterbox).
+        assertEquals(isScreenPortrait ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE,
                 activity.getConfiguration().orientation);
+        assertTrue(activity.isLetterboxedForFixedOrientationAndAspectRatio());
     }
 
     @Test
@@ -1964,17 +1965,17 @@
 
         // Non-resizable
         mAtm.mForceResizableActivities = false;
-        mAtm.mSizeCompatFreeform = false;
+        mAtm.mSupportsNonResizableMultiWindow = false;
         assertFalse(activity.supportsFreeform());
 
         // Force resizable
         mAtm.mForceResizableActivities = true;
-        mAtm.mSizeCompatFreeform = false;
+        mAtm.mSupportsNonResizableMultiWindow = false;
         assertTrue(activity.supportsFreeform());
 
         // Allow non-resizable
         mAtm.mForceResizableActivities = false;
-        mAtm.mSizeCompatFreeform = true;
+        mAtm.mSupportsNonResizableMultiWindow = true;
         assertTrue(activity.supportsFreeform());
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
index d13e4dc..7df17fd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
@@ -38,6 +38,7 @@
 
 import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS;
 import static com.android.server.wm.DisplayAreaPolicyBuilder.Feature;
+import static com.android.server.wm.DisplayAreaPolicyBuilder.KEY_ROOT_DISPLAY_AREA_ID;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -595,6 +596,17 @@
         assertThat(token.isDescendantOf(mRoot)).isTrue();
         assertThat(token.isDescendantOf(mGroupRoot1)).isFalse();
         assertThat(token.isDescendantOf(mGroupRoot2)).isFalse();
+
+        // When the window has options for target root id, attach it to the target root.
+        final Bundle options = new Bundle();
+        options.putInt(KEY_ROOT_DISPLAY_AREA_ID, mGroupRoot2.mFeatureId);
+        final WindowToken token2 = new WindowToken(mWms, mock(IBinder.class),
+                TYPE_STATUS_BAR, true /* persistOnEmpty */, mDisplayContent,
+                true /* ownerCanManageAppTokens */, false /* roundedCornerOverlay */,
+                false /* fromClientToken */, options);
+        policy.addWindow(token2);
+
+        assertThat(token2.isDescendantOf(mGroupRoot2)).isTrue();
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index dc702e6..137cf65 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -33,6 +33,7 @@
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
 import static android.view.Surface.ROTATION_0;
 import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
 import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
@@ -1443,7 +1444,7 @@
         // Assume the animation of PipTaskOrganizer is done and then commit fullscreen to task.
         pinnedTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
         displayContent.continueUpdateOrientationForDiffOrienLaunchingApp();
-        assertFalse(displayContent.getPinnedStackController().isPipActiveOrWindowingModeChanging());
+        assertFalse(displayContent.getPinnedTaskController().isPipActiveOrWindowingModeChanging());
         assertEquals(pinnedConfigOrientation, displayConfig.orientation);
 
         clearInvocations(mWm);
@@ -1454,7 +1455,7 @@
         assertFalse(displayContent.hasTopFixedRotationLaunchingApp());
         verify(mWm, atLeastOnce()).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt());
         assertEquals(homeConfigOrientation, displayConfig.orientation);
-        assertTrue(displayContent.getPinnedStackController().isPipActiveOrWindowingModeChanging());
+        assertTrue(displayContent.getPinnedTaskController().isPipActiveOrWindowingModeChanging());
     }
 
     @Test
@@ -1845,6 +1846,37 @@
         verify(t).show(mDisplayContent.mImeScreenshot);
     }
 
+    @Test
+    public void testRotateBounds_keepSamePhysicalPosition() {
+        final DisplayContent dc =
+                new TestDisplayContent.Builder(mAtm, 1000, 2000).build();
+        final Rect initBounds = new Rect(0, 0, 700, 1500);
+        final Rect rotateBounds = new Rect(initBounds);
+
+        // Rotate from 0 to 0
+        dc.rotateBounds(ROTATION_0, ROTATION_0, rotateBounds);
+
+        assertEquals(new Rect(0, 0, 700, 1500), rotateBounds);
+
+        // Rotate from 0 to 90
+        rotateBounds.set(initBounds);
+        dc.rotateBounds(ROTATION_0, ROTATION_90, rotateBounds);
+
+        assertEquals(new Rect(0, 300, 1500, 1000), rotateBounds);
+
+        // Rotate from 0 to 180
+        rotateBounds.set(initBounds);
+        dc.rotateBounds(ROTATION_0, ROTATION_180, rotateBounds);
+
+        assertEquals(new Rect(300, 500, 1000, 2000), rotateBounds);
+
+        // Rotate from 0 to 270
+        rotateBounds.set(initBounds);
+        dc.rotateBounds(ROTATION_0, ROTATION_270, rotateBounds);
+
+        assertEquals(new Rect(500, 0, 2000, 700), rotateBounds);
+    }
+
     private boolean isOptionsPanelAtRight(int displayId) {
         return (mWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT;
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 47cf53b..074ef36 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -323,4 +323,16 @@
         assertFalse(navBarSource.getFrame().isEmpty());
         assertTrue(imeSource.getFrame().contains(navBarSource.getFrame()));
     }
+
+    @UseTestDisplay
+    @Test
+    public void testDisplayPolicyNotCrash() {
+        final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
+
+        // Verify if modules initialized after DisplayContent ctr throws NPE.
+        displayPolicy.onDisplayInfoChanged(mDisplayInfo);
+        displayPolicy.onConfigurationChanged();
+        displayPolicy.onOverlayChangedLw();
+        displayPolicy.release();
+    }
 }
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 f91c9d0..e9c356d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
@@ -171,7 +171,7 @@
         final Rect activityBounds = new Rect(mFirstActivity.getBounds());
 
         // DAG is portrait (860x1200), so Task and Activity fill DAG.
-        assertThat(mFirstTask.isTaskLetterboxed()).isFalse();
+        assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
         assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
         assertThat(taskBounds).isEqualTo(dagBounds);
         assertThat(activityBounds).isEqualTo(taskBounds);
@@ -194,8 +194,8 @@
         final Rect activityConfigBounds =
                 new Rect(mFirstActivity.getConfiguration().windowConfiguration.getBounds());
 
-        // DAG is landscape (1200x860), Task fills parent
-        assertThat(mFirstTask.isTaskLetterboxed()).isFalse();
+        // DAG is landscape (1200x860), no fixed orientation letterbox
+        assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
         assertThat(mFirstActivity.inSizeCompatMode()).isTrue();
         assertThat(newDagBounds.width()).isEqualTo(dagBounds.height());
         assertThat(newDagBounds.height()).isEqualTo(dagBounds.width());
@@ -211,7 +211,7 @@
     }
 
     @Test
-    public void testLaunchLandscapeApp_taskIsLetterboxInDisplayAreaGroup() {
+    public void testLaunchLandscapeApp_activityIsLetterboxForFixedOrientationInDisplayAreaGroup() {
         mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
         mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
         mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
@@ -221,17 +221,18 @@
         final Rect taskBounds = new Rect(mFirstTask.getBounds());
         final Rect activityBounds = new Rect(mFirstActivity.getBounds());
 
-        // DAG is portrait (860x1200), so Task is letterbox (860x[860x860/1200=616])
-        assertThat(mFirstTask.isTaskLetterboxed()).isTrue();
+        // DAG is portrait (860x1200), and activity is letterboxed for fixed orientation
+        // (860x[860x860/1200=616]). Task fills DAG.
+        assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isTrue();
         assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
-        assertThat(taskBounds.width()).isEqualTo(dagBounds.width());
-        assertThat(taskBounds.height())
+        assertThat(taskBounds).isEqualTo(dagBounds);
+        assertThat(activityBounds.width()).isEqualTo(dagBounds.width());
+        assertThat(activityBounds.height())
                 .isEqualTo(dagBounds.width() * dagBounds.width() / dagBounds.height());
-        assertThat(activityBounds).isEqualTo(taskBounds);
     }
 
     @Test
-    public void testLaunchLandscapeApp_taskLetterboxBecomesActivityLetterboxAfterRotation() {
+    public void testLaunchLandscapeApp_fixedOrientationLetterboxBecomesSizeCompatAfterRotation() {
         mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
         mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
         mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
@@ -245,9 +246,8 @@
         final Rect newTaskBounds = new Rect(mFirstTask.getBounds());
         final Rect newActivityBounds = new Rect(mFirstActivity.getBounds());
 
-        // DAG is landscape (1200x860), Task fills parent
-        // Task letterbox size
-        assertThat(mFirstTask.isTaskLetterboxed()).isFalse();
+        // DAG is landscape (1200x860), no fixed orientation letterbox
+        assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
         assertThat(mFirstActivity.inSizeCompatMode()).isTrue();
         assertThat(newDagBounds.width()).isEqualTo(dagBounds.height());
         assertThat(newDagBounds.height()).isEqualTo(dagBounds.width());
@@ -311,7 +311,7 @@
     }
 
     @Test
-    public void testResizableFixedOrientationApp_taskLevelLetterboxing() {
+    public void testResizableFixedOrientationApp_fixedOrientationLetterboxing() {
         mFirstRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
         mSecondRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
 
@@ -324,7 +324,7 @@
         assertThat(mDisplay.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE);
         assertThat(mFirstRoot.getConfiguration().orientation).isEqualTo(ORIENTATION_PORTRAIT);
         assertThat(mFirstActivity.getConfiguration().orientation).isEqualTo(ORIENTATION_PORTRAIT);
-        assertThat(mFirstTask.isTaskLetterboxed()).isFalse();
+        assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
         assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
 
         // Launch portrait on second DAG
@@ -336,13 +336,13 @@
         assertThat(mDisplay.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_PORTRAIT);
         assertThat(mSecondRoot.getConfiguration().orientation).isEqualTo(ORIENTATION_LANDSCAPE);
         assertThat(mSecondActivity.getConfiguration().orientation).isEqualTo(ORIENTATION_LANDSCAPE);
-        assertThat(mSecondTask.isTaskLetterboxed()).isFalse();
+        assertThat(mSecondActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
         assertThat(mSecondActivity.inSizeCompatMode()).isFalse();
 
         // First activity is letterboxed in portrait as requested.
         assertThat(mFirstRoot.getConfiguration().orientation).isEqualTo(ORIENTATION_LANDSCAPE);
         assertThat(mFirstActivity.getConfiguration().orientation).isEqualTo(ORIENTATION_PORTRAIT);
-        assertThat(mFirstTask.isTaskLetterboxed()).isTrue();
+        assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isTrue();
         assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
 
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index be03603..80961d7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -416,6 +416,16 @@
         verify(navBar, atLeastOnce()).notifyInsetsChanged();
     }
 
+    @Test
+    public void testDispatchGlobalInsets() {
+        final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
+        getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
+        final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+        assertNull(getController().getInsetsForWindow(app).peekSource(ITYPE_NAVIGATION_BAR));
+        app.mAttrs.receiveInsetsIgnoringZOrder = true;
+        assertNotNull(getController().getInsetsForWindow(app).peekSource(ITYPE_NAVIGATION_BAR));
+    }
+
     private WindowState createTestWindow(String name) {
         final WindowState win = createWindow(null, TYPE_APPLICATION, name);
         win.setHasSurface(true);
diff --git a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
index d663b64..cc1869e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
@@ -454,7 +454,7 @@
         Settings.Secure.clearProviderForTest();
 
         // AND a password is set
-        when(mLockPatternUtils.isSecure(anyInt()))
+        when(mLockPatternUtils.isSecure(TEST_USER_ID))
                 .thenReturn(true);
 
         // AND there is a task record
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index e843dd7..b73c664 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -23,6 +23,7 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.view.Surface.ROTATION_180;
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
@@ -43,7 +44,6 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.same;
@@ -126,6 +126,7 @@
         // Put app window into freeform and then make it a compat app.
         final Rect bounds = new Rect(100, 100, 400, 600);
         mTask.setBounds(bounds);
+
         prepareUnresizable(mActivity, -1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
         assertEquals(bounds, mActivity.getBounds());
 
@@ -194,12 +195,7 @@
                 new TestDisplayContent.Builder(mAtm, 1000, 2000)
                         .setDensityDpi(200).build();
 
-        mActivity = new ActivityBuilder(mAtm)
-                .setTask(mTask)
-                .setResizeMode(RESIZE_MODE_UNRESIZEABLE)
-                .setMaxAspectRatio(1.5f)
-                .build();
-        mActivity.mVisibleRequested = true;
+        prepareUnresizable(mActivity, 1.5f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED);
 
         final Rect originalBounds = new Rect(mActivity.getBounds());
         final int originalDpi = mActivity.getConfiguration().densityDpi;
@@ -566,18 +562,18 @@
                 .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE)
                 .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
                 .build();
-        assertTrue(activity.shouldUseSizeCompatMode());
+        assertTrue(activity.shouldCreateCompatDisplayInsets());
 
         // The non-resizable activity should not be size compat because it is on a resizable task
         // in multi-window mode.
         mTask.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
-        assertFalse(activity.shouldUseSizeCompatMode());
+        assertFalse(activity.shouldCreateCompatDisplayInsets());
 
         // The non-resizable activity should not be size compat because the display support
         // changing windowing mode from fullscreen to freeform.
         mTask.mDisplayContent.setDisplayWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
         mTask.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
-        assertFalse(activity.shouldUseSizeCompatMode());
+        assertFalse(activity.shouldCreateCompatDisplayInsets());
     }
 
     @Test
@@ -597,7 +593,7 @@
                         SizeCompatTests.class.getName()))
                 .setUid(android.os.Process.myUid())
                 .build();
-        assertFalse(activity.shouldUseSizeCompatMode());
+        assertFalse(activity.shouldCreateCompatDisplayInsets());
     }
 
     @Test
@@ -653,7 +649,7 @@
     }
 
     @Test
-    public void testDisplayIgnoreOrientationRequest_fixedOrientationAppLaunchedInTaskLetterbox() {
+    public void testDisplayIgnoreOrientationRequest_fixedOrientationAppLaunchedLetterbox() {
         // Set up a display in landscape and ignoring orientation request.
         setUpDisplaySizeWithApp(2800, 1400);
         mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
@@ -662,7 +658,6 @@
         prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
 
         final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds());
-        final Rect taskBounds = new Rect(mTask.getBounds());
         final Rect activityBounds = new Rect(mActivity.getBounds());
 
         // Display shouldn't be rotated.
@@ -670,19 +665,19 @@
                 mActivity.mDisplayContent.getLastOrientation());
         assertTrue(displayBounds.width() > displayBounds.height());
 
-        // App should launch in task level letterboxing.
-        assertTrue(mTask.isTaskLetterboxed());
+        // App should launch in fixed orientation letterbox.
+        assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
         assertFalse(mActivity.inSizeCompatMode());
-        assertEquals(taskBounds, activityBounds);
 
-        // Task bounds should be 700x1400 with the ratio as the display.
-        assertEquals(displayBounds.height(), taskBounds.height());
+        // Activity bounds should be 700x1400 with the ratio as the display.
+        assertEquals(displayBounds.height(), activityBounds.height());
         assertEquals(displayBounds.height() * displayBounds.height() / displayBounds.width(),
-                taskBounds.width());
+                activityBounds.width());
     }
 
     @Test
-    public void testDisplayIgnoreOrientationRequest_taskLetterboxBecameSizeCompatAfterRotate() {
+    public void
+            testDisplayIgnoreOrientationRequest_orientationLetterboxBecameSizeCompatAfterRotate() {
         // Set up a display in landscape and ignoring orientation request.
         setUpDisplaySizeWithApp(2800, 1400);
         mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
@@ -700,7 +695,7 @@
         assertTrue(displayBounds.width() < displayBounds.height());
 
         // App should be in size compat.
-        assertFalse(mTask.isTaskLetterboxed());
+        assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
         assertScaled();
         assertEquals(activityBounds.width(), newActivityBounds.width());
         assertEquals(activityBounds.height(), newActivityBounds.height());
@@ -719,7 +714,7 @@
         Rect activityBounds = new Rect(mActivity.getBounds());
 
         // App should launch in fullscreen.
-        assertFalse(mTask.isTaskLetterboxed());
+        assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
         assertFalse(mActivity.inSizeCompatMode());
         assertEquals(displayBounds, activityBounds);
 
@@ -731,7 +726,7 @@
         assertTrue(displayBounds.width() > displayBounds.height());
 
         // App should be in size compat.
-        assertFalse(mTask.isTaskLetterboxed());
+        assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
         assertScaled();
 
         // App bounds should be 700x1400 with the ratio as the display.
@@ -741,7 +736,7 @@
     }
 
     @Test
-    public void testDisplayIgnoreOrientationRequest_newLaunchedOrientationAppInTaskLetterbox() {
+    public void testDisplayIgnoreOrientationRequest_newLaunchedOrientationAppInLetterbox() {
         // Set up a display in landscape and ignoring orientation request.
         setUpDisplaySizeWithApp(2800, 1400);
         final DisplayContent display = mActivity.mDisplayContent;
@@ -750,7 +745,7 @@
         // Portrait fixed app without max aspect.
         prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
 
-        assertTrue(mTask.isTaskLetterboxed());
+        assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
         assertFalse(mActivity.inSizeCompatMode());
 
         // Launch another portrait fixed app.
@@ -765,19 +760,19 @@
         // Update with new activity requested orientation and recompute bounds with no previous
         // size compat cache.
         verify(mTask).onDescendantOrientationChanged(same(newActivity));
-        verify(mTask).computeFullscreenBounds(any(), any());
 
         final Rect displayBounds = new Rect(display.getBounds());
         final Rect taskBounds = new Rect(mTask.getBounds());
         final Rect newActivityBounds = new Rect(newActivity.getBounds());
 
-        // Task and app bounds should be 700x1400 with the ratio as the display.
-        assertTrue(mTask.isTaskLetterboxed());
+        // Task and display bounds should be equal while activity should be letterboxed and
+        // has 700x1400 bounds with the ratio as the display.
+        assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
         assertFalse(newActivity.inSizeCompatMode());
-        assertEquals(taskBounds, newActivityBounds);
-        assertEquals(displayBounds.height(), taskBounds.height());
+        assertEquals(taskBounds, displayBounds);
+        assertEquals(displayBounds.height(), newActivityBounds.height());
         assertEquals(displayBounds.height() * displayBounds.height() / displayBounds.width(),
-                taskBounds.width());
+                newActivityBounds.width());
     }
 
     @Test
@@ -790,7 +785,7 @@
         // Portrait fixed app without max aspect.
         prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
 
-        assertTrue(mTask.isTaskLetterboxed());
+        assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
         assertFalse(mActivity.inSizeCompatMode());
 
         // Launch another portrait fixed app with max aspect ratio as 1.3.
@@ -806,21 +801,20 @@
         // Update with new activity requested orientation and recompute bounds with no previous
         // size compat cache.
         verify(mTask).onDescendantOrientationChanged(same(newActivity));
-        verify(mTask).computeFullscreenBounds(any(), any());
 
         final Rect displayBounds = new Rect(display.getBounds());
         final Rect taskBounds = new Rect(mTask.getBounds());
         final Rect newActivityBounds = new Rect(newActivity.getBounds());
 
-        // Task bounds should be (1400 / 1.3 = 1076)x1400 with the app requested ratio.
-        assertTrue(mTask.isTaskLetterboxed());
-        assertEquals(displayBounds.height(), taskBounds.height());
-        assertEquals((long) Math.rint(taskBounds.height() / newActivity.info.maxAspectRatio),
-                taskBounds.width());
+        // Task bounds should fill parent bounds.
+        assertEquals(displayBounds, taskBounds);
 
-        // App bounds should be fullscreen in Task bounds.
+        // Activity bounds should be (1400 / 1.3 = 1076)x1400 with the app requested ratio.
+        assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
         assertFalse(newActivity.inSizeCompatMode());
-        assertEquals(taskBounds, newActivityBounds);
+        assertEquals(displayBounds.height(), newActivityBounds.height());
+        assertEquals((long) Math.rint(newActivityBounds.height() / newActivity.info.maxAspectRatio),
+                newActivityBounds.width());
     }
 
     @Test
@@ -834,26 +828,23 @@
         prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
         clearInvocations(mActivity);
 
-        assertTrue(mTask.isTaskLetterboxed());
+        assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
         assertFalse(mActivity.inSizeCompatMode());
-        assertEquals(mTask.getLastTaskBoundsComputeActivity(), mActivity);
 
         // Rotate display to portrait.
         rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
 
         // App should be in size compat.
-        assertFalse(mTask.isTaskLetterboxed());
+        assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
         assertScaled();
-        assertEquals(mTask.getLastTaskBoundsComputeActivity(), mActivity);
 
         final Rect activityBounds = new Rect(mActivity.getBounds());
         mTask.resumeTopActivityUncheckedLocked(null /* prev */, null /* options */);
 
         // App still in size compat, and the bounds don't change.
         verify(mActivity, never()).clearSizeCompatMode();
-        assertFalse(mTask.isTaskLetterboxed());
+        assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
         assertScaled();
-        assertEquals(mTask.getLastTaskBoundsComputeActivity(), mActivity);
         assertEquals(activityBounds, mActivity.getBounds());
     }
 
@@ -867,22 +858,22 @@
         // Portrait fixed app.
         prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
 
-        // In Task letterbox
-        assertTrue(mTask.isTaskLetterboxed());
+        // In fixed orientation letterbox
+        assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
         assertFalse(mActivity.inSizeCompatMode());
 
         // Rotate display to portrait.
         rotateDisplay(display, ROTATION_90);
 
         // App should be in size compat.
-        assertFalse(mTask.isTaskLetterboxed());
+        assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
         assertScaled();
 
         // Rotate display to landscape.
         rotateDisplay(display, ROTATION_180);
 
         // In Task letterbox
-        assertTrue(mTask.isTaskLetterboxed());
+        assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
         assertFalse(mActivity.inSizeCompatMode());
     }
 
@@ -898,22 +889,22 @@
         // Landscape fixed app.
         prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_LANDSCAPE);
 
-        // In Task letterbox
-        assertTrue(mTask.isTaskLetterboxed());
+        // In fixed orientation letterbox
+        assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
         assertFalse(mActivity.inSizeCompatMode());
 
         // Rotate display to portrait.
         rotateDisplay(display, ROTATION_90);
 
         // App should be in size compat.
-        assertFalse(mTask.isTaskLetterboxed());
+        assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
         assertScaled();
 
         // Rotate display to landscape.
         rotateDisplay(display, ROTATION_180);
 
-        // In Task letterbox
-        assertTrue(mTask.isTaskLetterboxed());
+        // In fixed orientation letterbox
+        assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
         assertFalse(mActivity.inSizeCompatMode());
     }
 
@@ -972,21 +963,21 @@
         addWindowToActivity(mActivity);
         mActivity.mRootWindowContainer.performSurfacePlacement();
 
-        // Split screen is also in portrait [1000,1400], so Task should be in letterbox, and
-        // activity fills task.
-        assertEquals(ORIENTATION_LANDSCAPE, mTask.getConfiguration().orientation);
+        // Split screen is also in portrait [1000,1400], so activty should be in fixed orientation
+        // letterbox.
+        assertEquals(ORIENTATION_PORTRAIT, mTask.getConfiguration().orientation);
         assertEquals(ORIENTATION_LANDSCAPE, mActivity.getConfiguration().orientation);
         assertFitted();
-        assertTrue(mTask.isTaskLetterboxed());
+        assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
 
-        // Letterbox should fill the gap between the split screen and the letterboxed task.
+        // Letterbox should fill the gap between the split screen and the letterboxed activity.
         final Rect primarySplitBounds = new Rect(organizer.mPrimary.getBounds());
-        final Rect letterboxedTaskBounds = new Rect(mTask.getBounds());
-        assertTrue(primarySplitBounds.contains(letterboxedTaskBounds));
-        assertEquals(new Rect(letterboxedTaskBounds.left - primarySplitBounds.left,
-                letterboxedTaskBounds.top - primarySplitBounds.top,
-                primarySplitBounds.right - letterboxedTaskBounds.right,
-                primarySplitBounds.bottom - letterboxedTaskBounds.bottom),
+        final Rect letterboxedBounds = new Rect(mActivity.getBounds());
+        assertTrue(primarySplitBounds.contains(letterboxedBounds));
+        assertEquals(new Rect(letterboxedBounds.left - primarySplitBounds.left,
+                letterboxedBounds.top - primarySplitBounds.top,
+                primarySplitBounds.right - letterboxedBounds.right,
+                primarySplitBounds.bottom - letterboxedBounds.bottom),
                 mActivity.getLetterboxInsets());
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 4984799..5239462 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -473,6 +473,68 @@
                 mDefaultDisplay.getDefaultTaskDisplayArea(), mResult.mPreferredTaskDisplayArea);
     }
 
+    @Test
+    public void testRecalculateFreeformInitialBoundsWithOverrideDisplayArea() {
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
+                WINDOWING_MODE_FREEFORM);
+        final TaskDisplayArea secondaryDisplayArea = createTaskDisplayArea(freeformDisplay,
+                mWm, "SecondaryDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
+        secondaryDisplayArea.setBounds(DISPLAY_BOUNDS.width() / 2, 0,
+                        DISPLAY_BOUNDS.width(), DISPLAY_BOUNDS.height());
+        final Task launchRoot = createTaskStackOnTaskDisplayArea(WINDOWING_MODE_FULLSCREEN,
+                ACTIVITY_TYPE_STANDARD, secondaryDisplayArea);
+        launchRoot.mCreatedByOrganizer = true;
+        secondaryDisplayArea.setLaunchRootTask(launchRoot, new int[] { WINDOWING_MODE_FREEFORM },
+                new int[] { ACTIVITY_TYPE_STANDARD });
+        final Rect secondaryDAStableBounds = new Rect();
+        secondaryDisplayArea.getStableRect(secondaryDAStableBounds);
+
+        // Specify the display and provide a layout so that it will be set to freeform bounds.
+        final ActivityOptions options = ActivityOptions.makeBasic()
+                .setLaunchDisplayId(freeformDisplay.getDisplayId());
+        final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+                .setGravity(Gravity.LEFT).build();
+
+        assertEquals(RESULT_CONTINUE,
+                new CalculateRequestBuilder().setOptions(options).setLayout(layout).calculate());
+
+        assertEquals(secondaryDisplayArea, mResult.mPreferredTaskDisplayArea);
+        assertTrue(secondaryDAStableBounds.contains(mResult.mBounds));
+    }
+
+    @Test
+    public void testRecalculateFreeformInitialBoundsWithOverrideDisplayArea_unresizableApp() {
+        mAtm.mSupportsNonResizableMultiWindow = true;
+
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
+                WINDOWING_MODE_FREEFORM);
+        final TaskDisplayArea secondaryDisplayArea = createTaskDisplayArea(freeformDisplay,
+                mWm, "SecondaryDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
+        secondaryDisplayArea.setBounds(DISPLAY_BOUNDS.width() / 2, 0,
+                DISPLAY_BOUNDS.width(), DISPLAY_BOUNDS.height());
+        final Task launchRoot = createTaskStackOnTaskDisplayArea(WINDOWING_MODE_FULLSCREEN,
+                ACTIVITY_TYPE_STANDARD, secondaryDisplayArea);
+        launchRoot.mCreatedByOrganizer = true;
+        secondaryDisplayArea.setLaunchRootTask(launchRoot, new int[] { WINDOWING_MODE_FREEFORM },
+                new int[] { ACTIVITY_TYPE_STANDARD });
+        final Rect secondaryDAStableBounds = new Rect();
+        secondaryDisplayArea.getStableRect(secondaryDAStableBounds);
+
+        // The bounds will get updated for unresizable with opposite orientation on freeform display
+        final Rect displayBounds = new Rect(freeformDisplay.getBounds());
+        mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+        mActivity.info.screenOrientation = displayBounds.width() > displayBounds.height()
+                ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE;
+        final ActivityOptions options = ActivityOptions.makeBasic()
+                .setLaunchDisplayId(freeformDisplay.getDisplayId());
+
+        assertEquals(RESULT_CONTINUE,
+                new CalculateRequestBuilder().setOptions(options).calculate());
+
+        assertEquals(secondaryDisplayArea, mResult.mPreferredTaskDisplayArea);
+        assertTrue(secondaryDAStableBounds.contains(mResult.mBounds));
+    }
+
     // =====================================
     // Launch Windowing Mode Related Tests
     // =====================================
@@ -521,6 +583,7 @@
                 WINDOWING_MODE_FULLSCREEN);
     }
 
+
     @Test
     public void testKeepsPictureInPictureLaunchModeInOptions() {
         final TestDisplayContent freeformDisplay = createNewDisplayContent(
@@ -588,11 +651,14 @@
     }
 
     @Test
-    public void testNonEmptyLayoutInfersFreeformWithEmptySize() {
+    public void testLayoutWithGravityAndEmptySizeInfersFreeformAndRespectsCurrentSize() {
         final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
+        final Rect expectedLaunchBounds = new Rect(0, 0, 200, 100);
+
         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
+        mCurrent.mBounds.set(expectedLaunchBounds);
 
         final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
                 .setGravity(Gravity.LEFT).build();
@@ -600,6 +666,9 @@
         assertEquals(RESULT_CONTINUE,
                 new CalculateRequestBuilder().setLayout(layout).calculate());
 
+        assertEquals(expectedLaunchBounds.width(), mResult.mBounds.width());
+        assertEquals(expectedLaunchBounds.height(), mResult.mBounds.height());
+
         assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
                 WINDOWING_MODE_FREEFORM);
     }
@@ -661,7 +730,7 @@
 
     @Test
     public void testForceMaximizesUnresizeableApp() {
-        mAtm.mSizeCompatFreeform = false;
+        mAtm.mSupportsNonResizableMultiWindow = false;
         final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
@@ -683,12 +752,12 @@
     }
 
     @Test
-    public void testLaunchesAppInWindowOnFreeformDisplay() {
-        mAtm.mSizeCompatFreeform = true;
+    public void testLaunchesPortraitSizeCompatOnFreeformLandscapeDisplayWithFreeformSizeCompat() {
+        mAtm.mSupportsNonResizableMultiWindow = true;
         final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
 
-        Rect expectedLaunchBounds = new Rect(0, 0, 200, 100);
+        Rect expectedLaunchBounds = new Rect(0, 0, 100, 200);
 
         final ActivityOptions options = ActivityOptions.makeBasic();
         options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
@@ -699,6 +768,7 @@
         mCurrent.mBounds.set(expectedLaunchBounds);
 
         mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+        mActivity.info.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
 
         assertEquals(RESULT_CONTINUE,
                 new CalculateRequestBuilder().setOptions(options).calculate());
@@ -710,6 +780,38 @@
     }
 
     @Test
+    public void testLaunchesLandscapeSizeCompatOnFreeformLandscapeDisplayWithFreeformSizeCompat() {
+        mAtm.mSupportsNonResizableMultiWindow = true;
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
+                WINDOWING_MODE_FREEFORM);
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
+        mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+        mActivity.info.screenOrientation = SCREEN_ORIENTATION_LANDSCAPE;
+        assertEquals(RESULT_CONTINUE,
+                new CalculateRequestBuilder().setOptions(options).calculate());
+
+        assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+                WINDOWING_MODE_FREEFORM);
+    }
+
+    @Test
+    public void testLaunchesPortraitUnresizableOnFreeformDisplayWithFreeformSizeCompat() {
+        mAtm.mSupportsNonResizableMultiWindow = true;
+        final TestDisplayContent freeformDisplay = createNewDisplayContent(
+                WINDOWING_MODE_FREEFORM);
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
+        mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+        mActivity.info.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
+        assertEquals(RESULT_CONTINUE,
+                new CalculateRequestBuilder().setOptions(options).calculate());
+
+        assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+                WINDOWING_MODE_FREEFORM);
+    }
+
+    @Test
     public void testSkipsForceMaximizingAppsOnNonFreeformDisplay() {
         final ActivityOptions options = ActivityOptions.makeBasic();
         options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
@@ -1325,8 +1427,8 @@
         // This test case requires a relatively big app bounds to ensure the default size calculated
         // by letterbox won't be too small to hold the minimum width/height.
         configInsetsState(
-                freeformDisplay.getInsetsStateController().getRawInsetsState(),
-                DISPLAY_BOUNDS, new Rect(10, 10, 1910, 1070));
+                freeformDisplay.getInsetsStateController().getRawInsetsState(), freeformDisplay,
+                new Rect(10, 10, 1910, 1070));
 
         final ActivityOptions options = ActivityOptions.makeBasic();
         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
@@ -1547,15 +1649,17 @@
         display.setBounds(DISPLAY_BOUNDS);
         display.getConfiguration().densityDpi = DENSITY_DEFAULT;
         display.getConfiguration().orientation = ORIENTATION_LANDSCAPE;
-        configInsetsState(display.getInsetsStateController().getRawInsetsState(),
-                DISPLAY_BOUNDS, DISPLAY_STABLE_BOUNDS);
+        configInsetsState(display.getInsetsStateController().getRawInsetsState(), display,
+                DISPLAY_STABLE_BOUNDS);
         return display;
     }
 
     /**
      * Creates insets sources so that we can get the expected stable frame.
      */
-    private static void configInsetsState(InsetsState state, Rect displayFrame, Rect stableFrame) {
+    private static void configInsetsState(InsetsState state, DisplayContent display,
+            Rect stableFrame) {
+        final Rect displayFrame = display.getBounds();
         final int dl = displayFrame.left;
         final int dt = displayFrame.top;
         final int dr = displayFrame.right;
@@ -1578,6 +1682,8 @@
         if (sb < db) {
             state.getSource(ITYPE_NAVIGATION_BAR).setFrame(dl, sb, dr, db);
         }
+        // Recompute config and push to children.
+        display.onRequestedOverrideConfigurationChanged(display.getConfiguration());
     }
 
     private ActivityRecord createSourceActivity(TestDisplayContent display) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 0eb8c8d..d853b93 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -266,8 +266,9 @@
         root.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
         assertEquals(root, task.getRootActivity());
         assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getRootActivity().getOrientation());
-        assertThat(task.getBounds().width()).isLessThan(task.getBounds().height());
-        assertEquals(fullScreenBounds.height(), task.getBounds().height());
+        // Portrait orientation is enforced on activity level. Task should fill fullscreen bounds.
+        assertThat(task.getBounds().height()).isLessThan(task.getBounds().width());
+        assertEquals(fullScreenBounds, task.getBounds());
 
         // Top activity gets used
         final ActivityRecord top = new ActivityBuilder(mAtm).setTask(task).setParentTask(stack)
@@ -286,8 +287,11 @@
         // Fix the display orientation to portrait which is 90 degrees for the test display.
         dr.setUserRotation(USER_ROTATION_FREE, ROTATION_90);
 
-        assertThat(task.getBounds().width()).isGreaterThan(task.getBounds().height());
-        assertEquals(fullScreenBoundsPort.width(), task.getBounds().width());
+        // Fixed orientation request should be resolved on activity level. Task fills display
+        // bounds.
+        assertThat(task.getBounds().height()).isGreaterThan(task.getBounds().width());
+        assertThat(top.getBounds().width()).isGreaterThan(top.getBounds().height());
+        assertEquals(fullScreenBoundsPort, task.getBounds());
 
         // in FREEFORM, no constraint
         final Rect freeformBounds = new Rect(display.getBounds());
@@ -297,10 +301,11 @@
         task.setBounds(freeformBounds);
         assertEquals(freeformBounds, task.getBounds());
 
-        // FULLSCREEN letterboxes bounds
+        // FULLSCREEN letterboxes bounds on activity level, no constraint on task level.
         stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
-        assertThat(task.getBounds().width()).isGreaterThan(task.getBounds().height());
-        assertEquals(fullScreenBoundsPort.width(), task.getBounds().width());
+        assertThat(task.getBounds().height()).isGreaterThan(task.getBounds().width());
+        assertThat(top.getBounds().width()).isGreaterThan(top.getBounds().height());
+        assertEquals(fullScreenBoundsPort, task.getBounds());
 
         // FREEFORM restores bounds as before
         stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
@@ -327,9 +332,10 @@
 
         assertEquals(fullScreenBounds, task.getBounds());
 
-        // Setting app to fixed portrait fits within parent
+        // Setting app to fixed portrait fits within parent on activity level. Task fills parent.
         root.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
-        assertThat(task.getBounds().width()).isLessThan(task.getBounds().height());
+        assertThat(root.getBounds().width()).isLessThan(root.getBounds().height());
+        assertEquals(task.getBounds(), fullScreenBounds);
 
         assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getOrientation());
     }
@@ -424,7 +430,8 @@
         // to the input bounds.
         final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
         final ActivityRecord.CompatDisplayInsets compatIntsets =
-                new ActivityRecord.CompatDisplayInsets(display, activity);
+                new ActivityRecord.CompatDisplayInsets(
+                        display, activity, /* fixedOrientationBounds= */ null);
         task.computeConfigResourceOverrides(inOutConfig, parentConfig, compatIntsets);
 
         assertEquals(largerLandscapeBounds, inOutConfig.windowConfiguration.getAppBounds());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 1c0f640..c3eb5c4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -257,24 +257,4 @@
         task.resolveOverrideConfiguration(parentConfig);
         assertThat(resolvedOverride.getWindowingMode()).isEqualTo(WINDOWING_MODE_UNDEFINED);
     }
-
-    @Test
-    public void testCleanUpActivityReferences_clearLastTaskBoundsComputeActivity() {
-        final Task rootTask = createTaskStackOnDisplay(mDisplayContent);
-        final Task leafTask = createTaskInStack(rootTask, 0 /* userId */);
-        final ActivityRecord activity2 = createActivityRecord(mDisplayContent, leafTask);
-        final ActivityRecord activity1 = createActivityRecord(mDisplayContent, leafTask);
-        activity1.finishing = false;
-        leafTask.resolveOverrideConfiguration(rootTask.getConfiguration());
-
-        assertEquals(activity1, leafTask.getLastTaskBoundsComputeActivity());
-
-        leafTask.cleanUpActivityReferences(activity2);
-
-        assertNotNull(leafTask.getLastTaskBoundsComputeActivity());
-
-        leafTask.cleanUpActivityReferences(activity1);
-
-        assertNull(leafTask.getLastTaskBoundsComputeActivity());
-    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 99c96bd..bbb885eb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -984,6 +984,22 @@
     }
 
     @Test
+    public void testFreezeInsets() {
+        final Task stack = createTaskStackOnDisplay(mDisplayContent);
+        final ActivityRecord activity = createActivityRecord(mDisplayContent, stack);
+        final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win");
+
+        // Set visibility to false, verify the main window of the task will be set the frozen
+        // insets state immediately.
+        activity.setVisibility(false);
+        assertNotNull(win.getFrozenInsetsState());
+
+        // Now make it visible again, verify that the insets are immediately unfrozen.
+        activity.setVisibility(true);
+        assertNull(win.getFrozenInsetsState());
+    }
+
+    @Test
     public void testFreezeInsetsStateWhenAppTransition() {
         final Task stack = createTaskStackOnDisplay(mDisplayContent);
         final Task task = createTaskInStack(stack, 0 /* userId */);
@@ -996,15 +1012,20 @@
         sources.add(activity);
 
         // Simulate the task applying the exit transition, verify the main window of the task
-        // will be set the frozen insets state.
+        // will be set the frozen insets state before the animation starts
+        activity.setVisibility(false);
         task.applyAnimation(null, TRANSIT_OLD_TASK_CLOSE, false /* enter */,
                 false /* isVoiceInteraction */, sources);
         verify(win).freezeInsetsState();
 
-        // Simulate the task transition finished, verify the frozen insets state of the window
-        // will be reset.
+        // Simulate the task transition finished.
+        activity.commitVisibility(false, false);
         task.onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION,
                 task.mSurfaceAnimator.getAnimation());
+
+        // Now make it visible again, verify that the insets are immediately unfrozen even before
+        // transition starts.
+        activity.setVisibility(true);
         verify(win).clearFrozenInsetsState();
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
index 0dd8d23..18c8cf5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
@@ -18,7 +18,6 @@
 
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW;
-import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
 import static android.provider.Settings.Global.DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH;
@@ -119,20 +118,6 @@
     }
 
     @Test
-    public void testEnableSizeCompatFreeform() {
-        try (BoolSettingsSession enableSizeCompatFreeformSession = new
-                BoolSettingsSession(DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM)) {
-            final boolean enableSizeCompatFreeform =
-                    !enableSizeCompatFreeformSession.getSetting();
-            final Uri enableSizeCompatFreeformUri =
-                    enableSizeCompatFreeformSession.setSetting(enableSizeCompatFreeform);
-            mWm.mSettingsObserver.onChange(false, enableSizeCompatFreeformUri);
-
-            assertEquals(mWm.mAtmService.mSizeCompatFreeform, enableSizeCompatFreeform);
-        }
-    }
-
-    @Test
     public void testSupportsNonResizableMultiWindow() {
         try (BoolSettingsSession supportsNonResizableMultiWindowSession = new
                 BoolSettingsSession(DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW)) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 8969695..51aec65 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -251,7 +251,7 @@
 
         // Simulate the window is in split screen primary stack and the current state is
         // minimized and home stack is resizable, so that we should ignore input for the stack.
-        final DockedStackDividerController controller =
+        final DockedTaskDividerController controller =
                 mDisplayContent.getDockedDividerController();
         final Task stack = createTaskStackOnDisplay(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
                 ACTIVITY_TYPE_STANDARD, mDisplayContent);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index c13d6b1..ebc5c4f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -538,9 +538,8 @@
 
     /** Creates a {@link DisplayContent} and adds it to the system. */
     private DisplayContent createNewDisplay(DisplayInfo info, @DisplayImePolicy int imePolicy) {
-        final DisplayContent display =
+        final DisplayContent dc =
                 new TestDisplayContent.Builder(mAtm, info).build();
-        final DisplayContent dc = display.mDisplayContent;
         // this display can show IME.
         dc.mWmService.mDisplayWindowSettings.setDisplayImePolicy(dc, imePolicy);
         return dc;
diff --git a/services/texttospeech/Android.bp b/services/texttospeech/Android.bp
index bacc932..391ab89 100644
--- a/services/texttospeech/Android.bp
+++ b/services/texttospeech/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 filegroup {
     name: "services.texttospeech-sources",
     srcs: ["java/**/*.java"],
@@ -10,4 +19,4 @@
     defaults: ["platform_service_defaults"],
     srcs: [":services.texttospeech-sources"],
     libs: ["services.core"],
-}
\ No newline at end of file
+}
diff --git a/services/translation/Android.bp b/services/translation/Android.bp
index 804a617..f257f1b 100644
--- a/services/translation/Android.bp
+++ b/services/translation/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 filegroup {
     name: "services.translation-sources",
     srcs: ["java/**/*.java"],
@@ -10,4 +19,4 @@
     defaults: ["platform_service_defaults"],
     srcs: [":services.translation-sources"],
     libs: ["services.core"],
-}
\ No newline at end of file
+}
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerService.java b/services/translation/java/com/android/server/translation/TranslationManagerService.java
index 6aadd23..8874e0a 100644
--- a/services/translation/java/com/android/server/translation/TranslationManagerService.java
+++ b/services/translation/java/com/android/server/translation/TranslationManagerService.java
@@ -20,19 +20,29 @@
 import static android.content.Context.TRANSLATION_MANAGER_SERVICE;
 import static android.view.translation.TranslationManager.STATUS_SYNC_CALL_FAIL;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.Binder;
+import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
 import android.util.Slog;
 import android.view.autofill.AutofillId;
 import android.view.translation.ITranslationManager;
 import android.view.translation.TranslationSpec;
 import android.view.translation.UiTranslationManager.UiTranslationState;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.IResultReceiver;
 import com.android.server.infra.AbstractMasterSystemService;
 import com.android.server.infra.FrameworkResourcesServiceNameResolver;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.List;
 
 /**
@@ -48,6 +58,8 @@
 
     private static final String TAG = "TranslationManagerService";
 
+    private static final int MAX_TEMP_SERVICE_SUBSTITUTION_DURATION_MS = 2 * 60_000; // 2 minutes
+
     public TranslationManagerService(Context context) {
         // TODO: Discuss the disallow policy
         super(context, new FrameworkResourcesServiceNameResolver(context,
@@ -60,19 +72,82 @@
         return new TranslationManagerServiceImpl(this, mLock, resolvedUserId, disabled);
     }
 
+    @Override
+    protected void enforceCallingPermissionForManagement() {
+        getContext().enforceCallingPermission(MANAGE_UI_TRANSLATION, TAG);
+    }
+
+    @Override
+    protected int getMaximumTemporaryServiceDurationMs() {
+        return MAX_TEMP_SERVICE_SUBSTITUTION_DURATION_MS;
+    }
+
+    @Override
+    protected void dumpLocked(String prefix, PrintWriter pw) {
+        super.dumpLocked(prefix, pw);
+    }
+
     private void enforceCallerHasPermission(String permission) {
         final String msg = "Permission Denial from pid =" + Binder.getCallingPid() + ", uid="
                 + Binder.getCallingUid() + " doesn't hold " + permission;
         getContext().enforceCallingPermission(permission, msg);
     }
 
+    /** True if the currently set handler service is not overridden by the shell. */
+    @GuardedBy("mLock")
+    private boolean isDefaultServiceLocked(int userId) {
+        final String defaultServiceName = mServiceNameResolver.getDefaultServiceName(userId);
+        if (defaultServiceName == null) {
+            return false;
+        }
+
+        final String currentServiceName = mServiceNameResolver.getServiceName(userId);
+        return defaultServiceName.equals(currentServiceName);
+    }
+
+    /** True if the caller of the api is the same app which hosts the TranslationService. */
+    @GuardedBy("mLock")
+    private boolean isCalledByServiceAppLocked(int userId, @NonNull String methodName) {
+        final int callingUid = Binder.getCallingUid();
+
+        final String serviceName = mServiceNameResolver.getServiceName(userId);
+        if (serviceName == null) {
+            Slog.e(TAG, methodName + ": called by UID " + callingUid
+                    + ", but there's no service set for user " + userId);
+            return false;
+        }
+
+        final ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
+        if (serviceComponent == null) {
+            Slog.w(TAG, methodName + ": invalid service name: " + serviceName);
+            return false;
+        }
+
+        final String servicePackageName = serviceComponent.getPackageName();
+        final PackageManager pm = getContext().getPackageManager();
+        final int serviceUid;
+        try {
+            serviceUid = pm.getPackageUidAsUser(servicePackageName, userId);
+        } catch (PackageManager.NameNotFoundException e) {
+            Slog.w(TAG, methodName + ": could not verify UID for " + serviceName);
+            return false;
+        }
+        if (callingUid != serviceUid) {
+            Slog.e(TAG, methodName + ": called by UID " + callingUid + ", but service UID is "
+                    + serviceUid);
+            return false;
+        }
+        return true;
+    }
+
     final class TranslationManagerServiceStub extends ITranslationManager.Stub {
         @Override
         public void getSupportedLocales(IResultReceiver receiver, int userId)
                 throws RemoteException {
             synchronized (mLock) {
                 final TranslationManagerServiceImpl service = getServiceForUserLocked(userId);
-                if (service != null) {
+                if (service != null && (isDefaultServiceLocked(userId)
+                        || isCalledByServiceAppLocked(userId, "getSupportedLocales"))) {
                     service.getSupportedLocalesLocked(receiver);
                 } else {
                     Slog.v(TAG, "getSupportedLocales(): no service for " + userId);
@@ -86,7 +161,8 @@
                 int sessionId, IResultReceiver receiver, int userId) throws RemoteException {
             synchronized (mLock) {
                 final TranslationManagerServiceImpl service = getServiceForUserLocked(userId);
-                if (service != null) {
+                if (service != null && (isDefaultServiceLocked(userId)
+                        || isCalledByServiceAppLocked(userId, "onSessionCreated"))) {
                     service.onSessionCreatedLocked(sourceSpec, destSpec, sessionId, receiver);
                 } else {
                     Slog.v(TAG, "onSessionCreated(): no service for " + userId);
@@ -96,18 +172,58 @@
         }
 
         @Override
-        public void updateUiTranslationState(@UiTranslationState int state,
+        public void updateUiTranslationStateByTaskId(@UiTranslationState int state,
                 TranslationSpec sourceSpec, TranslationSpec destSpec, List<AutofillId> viewIds,
                 int taskId, int userId) {
+            // deprecated
             enforceCallerHasPermission(MANAGE_UI_TRANSLATION);
             synchronized (mLock) {
                 final TranslationManagerServiceImpl service = getServiceForUserLocked(userId);
-                if (service != null) {
-                    service.updateUiTranslationState(state, sourceSpec, destSpec, viewIds,
+                if (service != null && (isDefaultServiceLocked(userId)
+                        || isCalledByServiceAppLocked(userId,
+                        "updateUiTranslationStateByTaskId"))) {
+                    service.updateUiTranslationStateLocked(state, sourceSpec, destSpec, viewIds,
                             taskId);
                 }
             }
         }
+
+        @Override
+        public void updateUiTranslationState(@UiTranslationState int state,
+                TranslationSpec sourceSpec, TranslationSpec destSpec, List<AutofillId> viewIds,
+                IBinder token, int taskId, int userId) {
+            enforceCallerHasPermission(MANAGE_UI_TRANSLATION);
+            synchronized (mLock) {
+                final TranslationManagerServiceImpl service = getServiceForUserLocked(userId);
+                if (service != null && (isDefaultServiceLocked(userId)
+                        || isCalledByServiceAppLocked(userId, "updateUiTranslationState"))) {
+                    service.updateUiTranslationStateLocked(state, sourceSpec, destSpec, viewIds,
+                            token, taskId);
+                }
+            }
+        }
+
+        /**
+         * Dump the service state into the given stream. You run "adb shell dumpsys translation".
+        */
+        @Override
+        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            synchronized (mLock) {
+                dumpLocked("", pw);
+            }
+        }
+
+        @Override
+        public void onShellCommand(@Nullable FileDescriptor in,
+                @Nullable FileDescriptor out,
+                @Nullable FileDescriptor err,
+                @NonNull String[] args,
+                @Nullable ShellCallback callback,
+                @NonNull ResultReceiver resultReceiver) throws RemoteException {
+            new TranslationManagerServiceShellCommand(
+                    TranslationManagerService.this).exec(this, in, out, err, args, callback,
+                    resultReceiver);
+        }
     }
 
     @Override // from SystemService
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
index 38be85c..ab6ac12 100644
--- a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
+++ b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
@@ -23,6 +23,7 @@
 import android.content.ComponentName;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
+import android.os.IBinder;
 import android.os.RemoteException;
 import android.service.translation.TranslationServiceInfo;
 import android.util.Slog;
@@ -133,18 +134,40 @@
     }
 
     @GuardedBy("mLock")
-    public void updateUiTranslationState(@UiTranslationState int state,
+    public void updateUiTranslationStateLocked(@UiTranslationState int state,
             TranslationSpec sourceSpec, TranslationSpec destSpec, List<AutofillId> viewIds,
             int taskId) {
-        // TODO(b/177394471): use taskId as a temporary solution. The solution may use a token to
-        //  content capture manager service find the activitytoken. Then we can use this
-        //  activitytoken to find the activity to callback. But we need to change cc API so use
-        //  temporary solution.
-        final ActivityTokens tokens = mActivityTaskManagerInternal.getTopActivityForTask(taskId);
-        if (tokens == null) {
+        // deprecated
+        final ActivityTokens taskTopActivityTokens =
+                mActivityTaskManagerInternal.getTopActivityForTask(taskId);
+        if (taskTopActivityTokens == null) {
             Slog.w(TAG, "Unknown activity to query for update translation state.");
             return;
         }
+        updateUiTranslationStateByActivityTokens(taskTopActivityTokens, state, sourceSpec, destSpec,
+                viewIds);
+    }
+
+    @GuardedBy("mLock")
+    public void updateUiTranslationStateLocked(@UiTranslationState int state,
+            TranslationSpec sourceSpec, TranslationSpec destSpec, List<AutofillId> viewIds,
+            IBinder token, int taskId) {
+        // Get top activity for a given task id
+        final ActivityTokens taskTopActivityTokens =
+                mActivityTaskManagerInternal.getTopActivityForTask(taskId);
+        if (taskTopActivityTokens == null
+                || taskTopActivityTokens.getShareableActivityToken() != token) {
+            Slog.w(TAG, "Unknown activity or it was finished to query for update "
+                    + "translation state for token=" + token + " taskId=" + taskId);
+            return;
+        }
+        updateUiTranslationStateByActivityTokens(taskTopActivityTokens, state, sourceSpec, destSpec,
+                viewIds);
+    }
+
+    private void updateUiTranslationStateByActivityTokens(ActivityTokens tokens,
+            @UiTranslationState int state, TranslationSpec sourceSpec, TranslationSpec destSpec,
+            List<AutofillId> viewIds) {
         try {
             tokens.getApplicationThread().updateUiTranslationState(tokens.getActivityToken(), state,
                     sourceSpec, destSpec, viewIds);
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerServiceShellCommand.java b/services/translation/java/com/android/server/translation/TranslationManagerServiceShellCommand.java
new file mode 100644
index 0000000..ba1b390
--- /dev/null
+++ b/services/translation/java/com/android/server/translation/TranslationManagerServiceShellCommand.java
@@ -0,0 +1,79 @@
+/*
+ * 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.translation;
+
+import android.os.ShellCommand;
+
+import java.io.PrintWriter;
+
+/** Handles adb shell commands send to TranslationManagerService. */
+public class TranslationManagerServiceShellCommand extends ShellCommand {
+    private final TranslationManagerService mService;
+
+    TranslationManagerServiceShellCommand(TranslationManagerService service) {
+        mService = service;
+    }
+
+    @Override
+    public int onCommand(String cmd) {
+        if (cmd == null) {
+            return handleDefaultCommands(cmd);
+        }
+        final PrintWriter pw = getOutPrintWriter();
+        if ("set".equals(cmd)) {
+            return requestSet(pw);
+        }
+        return handleDefaultCommands(cmd);
+    }
+
+    private int requestSet(PrintWriter pw) {
+        final String what = getNextArgRequired();
+        if ("temporary-service".equals(what)) {
+            return setTemporaryService(pw);
+        }
+        pw.println("Invalid set: " + what);
+        return -1;
+    }
+
+    private int setTemporaryService(PrintWriter pw) {
+        final int userId = Integer.parseInt(getNextArgRequired());
+        final String serviceName = getNextArg();
+        if (serviceName == null) {
+            mService.resetTemporaryService(userId);
+            return 0;
+        }
+        final int duration = Integer.parseInt(getNextArgRequired());
+        mService.setTemporaryService(userId, serviceName, duration);
+        pw.println("TranslationService temporarily set to " + serviceName + " for "
+                + duration + "ms");
+        return 0;
+    }
+
+    @Override
+    public void onHelp() {
+        try (PrintWriter pw = getOutPrintWriter();) {
+            pw.println("Translation Service (translation) commands:");
+            pw.println("  help");
+            pw.println("    Prints this help text.");
+            pw.println("");
+            pw.println("  set temporary-service USER_ID [COMPONENT_NAME DURATION]");
+            pw.println("    Temporarily (for DURATION ms) changes the service implementation.");
+            pw.println("    To reset, call with just the USER_ID argument.");
+            pw.println("");
+        }
+    }
+}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 35e65c1..ed71d17 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -22,25 +22,49 @@
 import android.content.Intent;
 import android.hardware.soundtrigger.IRecognitionStatusCallback;
 import android.hardware.soundtrigger.SoundTrigger;
+import android.media.AudioAttributes;
+import android.media.AudioRecord;
+import android.media.MediaRecorder;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.service.voice.AlwaysOnHotwordDetector;
 import android.service.voice.HotwordDetectionService;
 import android.service.voice.IDspHotwordDetectionCallback;
 import android.service.voice.IHotwordDetectionService;
+import android.util.Pair;
 import android.util.Slog;
 
 import com.android.internal.app.IHotwordRecognitionStatusCallback;
 import com.android.internal.infra.ServiceConnector;
 
+import java.io.IOException;
+import java.io.OutputStream;
 import java.io.PrintWriter;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
 
 /**
  * A class that provides the communication with the HotwordDetectionService.
  */
 final class HotwordDetectionConnection {
-    static final String TAG = "HotwordDetectionConnection";
+    private static final String TAG = "HotwordDetectionConnection";
     // TODO (b/177502877): Set the Debug flag to false before shipping.
-    static final boolean DEBUG = true;
+    private static final boolean DEBUG = true;
+
+    // Number of bytes per sample of audio (which is a short).
+    private static final int BYTES_PER_SAMPLE = 2;
+    // TODO: These constants need to be refined.
+    private static final long VALIDATION_TIMEOUT_MILLIS = 3000;
+    private static final long VOICE_INTERACTION_TIMEOUT_TO_OPEN_MIC_MILLIS = 2000;
+    private static final int MAX_STREAMING_SECONDS = 10;
+
+    private final Executor mAudioCopyExecutor = Executors.newCachedThreadPool();
+    // TODO: This may need to be a Handler(looper)
+    private final ScheduledExecutorService mScheduledExecutorService =
+            Executors.newSingleThreadScheduledExecutor();
 
     final Object mLock;
     final ComponentName mDetectionComponentName;
@@ -93,42 +117,106 @@
         }
     }
 
-    private void detectFromDspSource(int sessionId, IDspHotwordDetectionCallback callback) {
+    private void detectFromDspSource(SoundTrigger.KeyphraseRecognitionEvent recognitionEvent,
+            IHotwordRecognitionStatusCallback externalCallback) {
         if (DEBUG) {
             Slog.d(TAG, "detectFromDspSource");
         }
+
+        AudioRecord record = createAudioRecord(recognitionEvent);
+
+        Pair<ParcelFileDescriptor, ParcelFileDescriptor> clientPipe = createPipe();
+
+        if (clientPipe == null) {
+            // Error.
+            // Need to propagate as unknown error or something?
+            return;
+        }
+        ParcelFileDescriptor audioSink = clientPipe.second;
+        ParcelFileDescriptor clientRead = clientPipe.first;
+
+        record.startRecording();
+
+        mAudioCopyExecutor.execute(() -> {
+            try (OutputStream fos =
+                         new ParcelFileDescriptor.AutoCloseOutputStream(audioSink)) {
+                byte[] buffer = new byte[1024];
+
+                while (true) {
+                    int bytesRead = record.read(buffer, 0, 1024);
+
+                    if (bytesRead < 0) {
+                        break;
+                    }
+
+                    fos.write(buffer, 0, bytesRead);
+                }
+            } catch (IOException e) {
+                Slog.w(TAG, "Failed supplying audio data to validator", e);
+            }
+        });
+
+        Runnable cancellingJob = () -> {
+            record.stop();
+            bestEffortCloseFileDescriptor(audioSink);
+            // TODO: consider calling externalCallback.onRejected(ERROR_TIMEOUT).
+        };
+
+        ScheduledFuture<?> cancelingFuture =
+                mScheduledExecutorService.schedule(
+                        cancellingJob, VALIDATION_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+
+        // TODO: consider making this a non-anonymous class.
+        IDspHotwordDetectionCallback internalCallback = new IDspHotwordDetectionCallback.Stub() {
+            @Override
+            public void onDetected() throws RemoteException {
+                if (DEBUG) {
+                    Slog.d(TAG, "onDetected");
+                }
+                bestEffortCloseFileDescriptor(audioSink);
+                cancelingFuture.cancel(true);
+
+                // Give 2 more seconds for the interactor to start consuming the mic. If it fails to
+                // do so under the given time, we'll force-close the mic to make sure resources are
+                // freed up.
+                // TODO: consider modelling these 2 seconds in the API.
+                mScheduledExecutorService.schedule(
+                        cancellingJob,
+                        VOICE_INTERACTION_TIMEOUT_TO_OPEN_MIC_MILLIS,
+                        TimeUnit.MILLISECONDS);
+
+                externalCallback.onKeyphraseDetected(recognitionEvent);
+            }
+
+            @Override
+            public void onRejected() throws RemoteException {
+                if (DEBUG) {
+                    Slog.d(TAG, "onRejected");
+                }
+                cancelingFuture.cancel(true);
+                externalCallback.onRejected(
+                        AlwaysOnHotwordDetector.HOTWORD_DETECTION_FALSE_ALERT);
+            }
+        };
+
         mRemoteHotwordDetectionService.run(
-                service -> service.detectFromDspSource(sessionId, callback));
+                service -> service.detectFromDspSource(
+                        clientRead,
+                        recognitionEvent.getCaptureFormat(),
+                        VALIDATION_TIMEOUT_MILLIS,
+                        internalCallback));
+        bestEffortCloseFileDescriptor(clientRead);
     }
 
     static final class SoundTriggerCallback extends IRecognitionStatusCallback.Stub {
         private SoundTrigger.KeyphraseRecognitionEvent mRecognitionEvent;
         private final HotwordDetectionConnection mHotwordDetectionConnection;
         private final IHotwordRecognitionStatusCallback mExternalCallback;
-        private final IDspHotwordDetectionCallback mInternalCallback;
 
         SoundTriggerCallback(IHotwordRecognitionStatusCallback callback,
                 HotwordDetectionConnection connection) {
             mHotwordDetectionConnection = connection;
             mExternalCallback = callback;
-            mInternalCallback = new IDspHotwordDetectionCallback.Stub() {
-                @Override
-                public void onDetected() throws RemoteException {
-                    if (DEBUG) {
-                        Slog.d(TAG, "onDetected");
-                    }
-                    mExternalCallback.onKeyphraseDetected(mRecognitionEvent);
-                }
-
-                @Override
-                public void onRejected() throws RemoteException {
-                    if (DEBUG) {
-                        Slog.d(TAG, "onRejected");
-                    }
-                    mExternalCallback.onRejected(
-                            AlwaysOnHotwordDetector.HOTWORD_DETECTION_FALSE_ALERT);
-                }
-            };
         }
 
         @Override
@@ -142,7 +230,7 @@
             if (useHotwordDetectionService) {
                 mRecognitionEvent = recognitionEvent;
                 mHotwordDetectionConnection.detectFromDspSource(
-                        recognitionEvent.getCaptureSession(), mInternalCallback);
+                        recognitionEvent, mExternalCallback);
             } else {
                 mExternalCallback.onKeyphraseDetected(recognitionEvent);
             }
@@ -171,6 +259,48 @@
         }
     }
 
+    // TODO: figure out if we need to let the client configure some of the parameters.
+    private static AudioRecord createAudioRecord(
+            @NonNull SoundTrigger.KeyphraseRecognitionEvent recognitionEvent) {
+        int sampleRate = recognitionEvent.getCaptureFormat().getSampleRate();
+        return new AudioRecord(
+                new AudioAttributes.Builder()
+                        .setInternalCapturePreset(MediaRecorder.AudioSource.HOTWORD).build(),
+                recognitionEvent.getCaptureFormat(),
+                getBufferSizeInBytes(sampleRate, MAX_STREAMING_SECONDS),
+                recognitionEvent.getCaptureSession());
+    }
+
+    /**
+     * Returns the number of bytes required to store {@code bufferLengthSeconds} of audio sampled at
+     * {@code sampleRate} Hz, using the format returned by DSP audio capture.
+     */
+    private static int getBufferSizeInBytes(int sampleRate, int bufferLengthSeconds) {
+        return BYTES_PER_SAMPLE * sampleRate * bufferLengthSeconds;
+    }
+
+    private static Pair<ParcelFileDescriptor, ParcelFileDescriptor> createPipe() {
+        ParcelFileDescriptor[] fileDescriptors;
+        try {
+            fileDescriptors = ParcelFileDescriptor.createPipe();
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to create audio stream pipe", e);
+            return null;
+        }
+
+        return Pair.create(fileDescriptors[0], fileDescriptors[1]);
+    }
+
+    private static void bestEffortCloseFileDescriptor(ParcelFileDescriptor fd) {
+        try {
+            fd.close();
+        } catch (IOException e) {
+            if (DEBUG) {
+                Slog.w(TAG, "Failed closing file descriptor", e);
+            }
+        }
+    }
+
     public void dump(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("mBound="); pw.println(mBound);
     }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 8628f89..dce63eb 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -76,6 +76,7 @@
 import android.util.Log;
 import android.util.Slog;
 
+import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IHotwordRecognitionStatusCallback;
 import com.android.internal.app.IVoiceActionCheckCallback;
@@ -643,6 +644,10 @@
         }
 
         ComponentName findAvailRecognizer(String prefPackage, int userHandle) {
+            if (prefPackage == null) {
+                prefPackage = getDefaultRecognizer();
+            }
+
             List<ResolveInfo> available =
                     mContext.getPackageManager().queryIntentServicesAsUser(
                             new Intent(RecognitionService.SERVICE_INTERFACE),
@@ -670,6 +675,12 @@
             }
         }
 
+        @Nullable
+        public String getDefaultRecognizer() {
+            String recognizer = mContext.getString(R.string.config_systemSpeechRecognizer);
+            return TextUtils.isEmpty(recognizer) ? null : recognizer;
+        }
+
         ComponentName getCurRecognizer(int userHandle) {
             String curRecognizer = Settings.Secure.getStringForUser(
                     mContext.getContentResolver(),
diff --git a/telecomm/java/android/telecom/BluetoothCallQualityReport.aidl b/telecomm/java/android/telecom/BluetoothCallQualityReport.aidl
new file mode 100644
index 0000000..685fe9c
--- /dev/null
+++ b/telecomm/java/android/telecom/BluetoothCallQualityReport.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.telecom;
+
+/**
+ * {@hide}
+ */
+parcelable BluetoothCallQualityReport;
diff --git a/telecomm/java/android/telecom/BluetoothCallQualityReport.java b/telecomm/java/android/telecom/BluetoothCallQualityReport.java
index 10339a8..8703d84 100644
--- a/telecomm/java/android/telecom/BluetoothCallQualityReport.java
+++ b/telecomm/java/android/telecom/BluetoothCallQualityReport.java
@@ -24,6 +24,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.Objects;
+
 /**
  * This class represents the quality report that bluetooth framework sends
  * whenever there's a bad voice quality is detected from their side.
@@ -145,6 +147,26 @@
                 }
             };
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        BluetoothCallQualityReport that = (BluetoothCallQualityReport) o;
+        return mSentTimestampMillis == that.mSentTimestampMillis
+                && mChoppyVoice == that.mChoppyVoice && mRssiDbm == that.mRssiDbm
+                && mSnrDb == that.mSnrDb
+                && mRetransmittedPacketsCount == that.mRetransmittedPacketsCount
+                && mPacketsNotReceivedCount == that.mPacketsNotReceivedCount
+                && mNegativeAcknowledgementCount == that.mNegativeAcknowledgementCount;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mSentTimestampMillis, mChoppyVoice, mRssiDbm, mSnrDb,
+                mRetransmittedPacketsCount, mPacketsNotReceivedCount,
+                mNegativeAcknowledgementCount);
+    }
+
     /**
      * Builder class for {@link ConnectionRequest}
      */
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 044ea80..2a5ddfd 100755
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -267,6 +267,64 @@
     public static final String EVENT_HANDOVER_FAILED =
             "android.telecom.event.HANDOVER_FAILED";
 
+    /**
+     * Event reported from the Telecom stack to report an in-call diagnostic message which the
+     * dialer app may opt to display to the user.  A diagnostic message is used to communicate
+     * scenarios the device has detected which may impact the quality of the ongoing call.
+     * <p>
+     * For example a problem with a bluetooth headset may generate a recommendation for the user to
+     * try using the speakerphone instead, or if the device detects it has entered a poor service
+     * area, the user might be warned so that they can finish their call prior to it dropping.
+     * <p>
+     * A diagnostic message is considered persistent in nature.  When the user enters a poor service
+     * area, for example, the accompanying diagnostic message persists until they leave the area
+     * of poor service.  Each message is accompanied with a {@link #EXTRA_DIAGNOSTIC_MESSAGE_ID}
+     * which uniquely identifies the diagnostic condition being reported.  The framework raises a
+     * call event of type {@link #EVENT_CLEAR_DIAGNOSTIC_MESSAGE} when the condition reported has
+     * been cleared.  The dialer app should display the diagnostic message until it is cleared.
+     * If multiple diagnostic messages are sent with different IDs (which have not yet been cleared)
+     * the dialer app should prioritize the most recently received message, but still provide the
+     * user with a means to review past messages.
+     * <p>
+     * The text of the message is found in {@link #EXTRA_DIAGNOSTIC_MESSAGE} in the form of a human
+     * readable {@link CharSequence} which is intended for display in the call UX.
+     * <p>
+     * The telecom framework audibly notifies the user of the presence of a diagnostic message, so
+     * the dialer app needs only to concern itself with visually displaying the message.
+     * <p>
+     * The dialer app receives this event via
+     * {@link Call.Callback#onConnectionEvent(Call, String, Bundle)}.
+     */
+    public static final String EVENT_DISPLAY_DIAGNOSTIC_MESSAGE =
+            "android.telecom.event.DISPLAY_DIAGNOSTIC_MESSAGE";
+
+    /**
+     * Event reported from the telecom framework when a diagnostic message previously raised with
+     * {@link #EVENT_DISPLAY_DIAGNOSTIC_MESSAGE} has cleared and is no longer pertinent.
+     * <p>
+     * The {@link #EXTRA_DIAGNOSTIC_MESSAGE_ID} indicates the diagnostic message which has been
+     * cleared.
+     * <p>
+     * The dialer app receives this event via
+     * {@link Call.Callback#onConnectionEvent(Call, String, Bundle)}.
+     */
+    public static final String EVENT_CLEAR_DIAGNOSTIC_MESSAGE =
+            "android.telecom.event.CLEAR_DIAGNOSTIC_MESSAGE";
+
+    /**
+     * Integer extra representing a message ID for a message posted via
+     * {@link #EVENT_DISPLAY_DIAGNOSTIC_MESSAGE}.  Used to ensure that the dialer app knows when
+     * the message in question has cleared via {@link #EVENT_CLEAR_DIAGNOSTIC_MESSAGE}.
+     */
+    public static final String EXTRA_DIAGNOSTIC_MESSAGE_ID =
+            "android.telecom.extra.DIAGNOSTIC_MESSAGE_ID";
+
+    /**
+     * {@link CharSequence} extra used with {@link #EVENT_DISPLAY_DIAGNOSTIC_MESSAGE}.  This is the
+     * diagnostic message the dialer app should display.
+     */
+    public static final String EXTRA_DIAGNOSTIC_MESSAGE =
+            "android.telecom.extra.DIAGNOSTIC_MESSAGE";
 
     /**
      * Reject reason used with {@link #reject(int)} to indicate that the user is rejecting this
diff --git a/telecomm/java/android/telecom/CallDiagnosticService.java b/telecomm/java/android/telecom/CallDiagnosticService.java
new file mode 100644
index 0000000..201c5db
--- /dev/null
+++ b/telecomm/java/android/telecom/CallDiagnosticService.java
@@ -0,0 +1,328 @@
+/*
+ * 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.telecom;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+
+import com.android.internal.telecom.ICallDiagnosticService;
+import com.android.internal.telecom.ICallDiagnosticServiceAdapter;
+
+import java.util.Map;
+
+/**
+ * The platform supports a single OEM provided {@link CallDiagnosticService}, as defined by the
+ * {@code call_diagnostic_service_package_name} key in the
+ * {@code packages/services/Telecomm/res/values/config.xml} file.  An OEM can use this API to help
+ * provide more actionable information about calling issues the user encounters during and after
+ * a call.
+ *
+ * <h1>Manifest Declaration</h1>
+ * The following is an example of how to declare the service entry in the
+ * {@link CallDiagnosticService} manifest file:
+ * <pre>
+ * {@code
+ * <service android:name="your.package.YourCallDiagnosticServiceImplementation"
+ *          android:permission="android.permission.BIND_CALL_DIAGNOSTIC_SERVICE">
+ *      <intent-filter>
+ *          <action android:name="android.telecom.CallDiagnosticService"/>
+ *      </intent-filter>
+ * </service>
+ * }
+ * </pre>
+ * @hide
+ */
+@SystemApi
+public abstract class CallDiagnosticService extends Service {
+
+    /**
+     * Binder stub implementation which handles incoming requests from Telecom.
+     */
+    private final class CallDiagnosticServiceBinder extends ICallDiagnosticService.Stub {
+
+        @Override
+        public void setAdapter(ICallDiagnosticServiceAdapter adapter) throws RemoteException {
+            handleSetAdapter(adapter);
+        }
+
+        @Override
+        public void initializeDiagnosticCall(ParcelableCall call) throws RemoteException {
+            handleCallAdded(call);
+        }
+
+        @Override
+        public void updateCall(ParcelableCall call) throws RemoteException {
+            handleCallUpdated(call);
+        }
+
+        @Override
+        public void removeDiagnosticCall(String callId) throws RemoteException {
+            handleCallRemoved(callId);
+        }
+
+        @Override
+        public void updateCallAudioState(CallAudioState callAudioState) throws RemoteException {
+            onCallAudioStateChanged(callAudioState);
+        }
+
+        @Override
+        public void receiveDeviceToDeviceMessage(String callId, int message, int value) {
+            handleReceivedD2DMessage(callId, message, value);
+        }
+
+        @Override
+        public void receiveBluetoothCallQualityReport(BluetoothCallQualityReport qualityReport)
+                throws RemoteException {
+            handleBluetoothCallQualityReport(qualityReport);
+        }
+    }
+
+    /**
+     * Listens to events raised by a {@link DiagnosticCall}.
+     */
+    private android.telecom.DiagnosticCall.Listener mDiagnosticCallListener =
+            new android.telecom.DiagnosticCall.Listener() {
+
+                @Override
+                public void onSendDeviceToDeviceMessage(DiagnosticCall diagnosticCall,
+                        @DiagnosticCall.MessageType int message, int value) {
+                    handleSendDeviceToDeviceMessage(diagnosticCall, message, value);
+                }
+
+                @Override
+                public void onDisplayDiagnosticMessage(DiagnosticCall diagnosticCall, int messageId,
+                        CharSequence message) {
+                    handleDisplayDiagnosticMessage(diagnosticCall, messageId, message);
+                }
+
+                @Override
+                public void onClearDiagnosticMessage(DiagnosticCall diagnosticCall, int messageId) {
+                    handleClearDiagnosticMessage(diagnosticCall, messageId);
+                }
+            };
+
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE = "android.telecom.CallDiagnosticService";
+
+    /**
+     * Map which tracks the Telecom calls received from the Telecom stack.
+     */
+    private final Map<String, Call.Details> mCallByTelecomCallId = new ArrayMap<>();
+    private final Map<String, DiagnosticCall> mDiagnosticCallByTelecomCallId = new ArrayMap<>();
+    private ICallDiagnosticServiceAdapter mAdapter;
+
+    @Nullable
+    @Override
+    public IBinder onBind(@NonNull Intent intent) {
+        Log.i(this, "onBind!");
+        return new CallDiagnosticServiceBinder();
+    }
+
+    /**
+     * Telecom calls this method on the {@link CallDiagnosticService} with details about a new call
+     * which was added to Telecom.
+     * <p>
+     * The {@link CallDiagnosticService} returns an implementation of {@link DiagnosticCall} to be
+     * used for the lifespan of this call.
+     *
+     * @param call The details of the new call.
+     * @return An instance of {@link DiagnosticCall} which the {@link CallDiagnosticService}
+     * provides to be used for the lifespan of the call.
+     * @throws IllegalArgumentException if a {@code null} {@link DiagnosticCall} is returned.
+     */
+    public abstract @NonNull DiagnosticCall onInitializeDiagnosticCall(@NonNull
+            android.telecom.Call.Details call);
+
+    /**
+     * Telecom calls this method when a previous created {@link DiagnosticCall} is no longer needed.
+     * This happens when Telecom is no longer tracking the call in question.
+     * @param call The diagnostic call which is no longer tracked by Telecom.
+     */
+    public abstract void onRemoveDiagnosticCall(@NonNull DiagnosticCall call);
+
+    /**
+     * Telecom calls this method when the audio routing or available audio route information
+     * changes.
+     * <p>
+     * Audio state is common to all calls.
+     *
+     * @param audioState The new audio state.
+     */
+    public abstract void onCallAudioStateChanged(
+            @NonNull CallAudioState audioState);
+
+    /**
+     * Telecom calls this method when a {@link BluetoothCallQualityReport} is received from the
+     * bluetooth stack.
+     * @param qualityReport the {@link BluetoothCallQualityReport}.
+     */
+    public abstract void onBluetoothCallQualityReportReceived(
+            @NonNull BluetoothCallQualityReport qualityReport);
+
+    /**
+     * Handles a request from Telecom to set the adapater used to communicate back to Telecom.
+     * @param adapter
+     */
+    private void handleSetAdapter(@NonNull ICallDiagnosticServiceAdapter adapter) {
+        mAdapter = adapter;
+    }
+
+    /**
+     * Handles a request from Telecom to add a new call.
+     * @param parcelableCall
+     */
+    private void handleCallAdded(@NonNull ParcelableCall parcelableCall) {
+        String telecomCallId = parcelableCall.getId();
+        Log.i(this, "handleCallAdded: callId=%s - added", telecomCallId);
+        Call.Details newCallDetails = Call.Details.createFromParcelableCall(parcelableCall);
+        mCallByTelecomCallId.put(telecomCallId, newCallDetails);
+
+        DiagnosticCall diagnosticCall = onInitializeDiagnosticCall(newCallDetails);
+        if (diagnosticCall == null) {
+            throw new IllegalArgumentException("A valid DiagnosticCall instance was not provided.");
+        }
+        diagnosticCall.setListener(mDiagnosticCallListener);
+        diagnosticCall.setCallId(telecomCallId);
+        mDiagnosticCallByTelecomCallId.put(telecomCallId, diagnosticCall);
+    }
+
+    /**
+     * Handles an update to {@link Call.Details} notified by Telecom.
+     * Caches the call details and notifies the {@link DiagnosticCall} of the change via
+     * {@link DiagnosticCall#onCallDetailsChanged(Call.Details)}.
+     * @param parcelableCall the new parceled call details from Telecom.
+     */
+    private void handleCallUpdated(@NonNull ParcelableCall parcelableCall) {
+        String telecomCallId = parcelableCall.getId();
+        Log.i(this, "handleCallUpdated: callId=%s - updated", telecomCallId);
+        Call.Details newCallDetails = Call.Details.createFromParcelableCall(parcelableCall);
+
+        DiagnosticCall diagnosticCall = mDiagnosticCallByTelecomCallId.get(telecomCallId);
+        mCallByTelecomCallId.put(telecomCallId, newCallDetails);
+        diagnosticCall.handleCallUpdated(newCallDetails);
+    }
+
+    /**
+     * Handles a request from Telecom to remove an existing call.
+     * @param telecomCallId
+     */
+    private void handleCallRemoved(@NonNull String telecomCallId) {
+        Log.i(this, "handleCallRemoved: callId=%s - removed", telecomCallId);
+
+        if (mCallByTelecomCallId.containsKey(telecomCallId)) {
+            mCallByTelecomCallId.remove(telecomCallId);
+        }
+        if (mDiagnosticCallByTelecomCallId.containsKey(telecomCallId)) {
+            DiagnosticCall call = mDiagnosticCallByTelecomCallId.remove(telecomCallId);
+            // Inform the service of the removed call.
+            onRemoveDiagnosticCall(call);
+        }
+    }
+
+    /**
+     * Handles an incoming device to device message received from Telecom.  Notifies the
+     * {@link DiagnosticCall} via {@link DiagnosticCall#onReceiveDeviceToDeviceMessage(int, int)}.
+     * @param callId
+     * @param message
+     * @param value
+     */
+    private void handleReceivedD2DMessage(@NonNull String callId, int message, int value) {
+        Log.i(this, "handleReceivedD2DMessage: callId=%s, msg=%d/%d", callId, message, value);
+        DiagnosticCall diagnosticCall = mDiagnosticCallByTelecomCallId.get(callId);
+        diagnosticCall.onReceiveDeviceToDeviceMessage(message, value);
+    }
+
+    /**
+     * Handles an incoming bluetooth call quality report from Telecom.  Notifies via
+     * {@link CallDiagnosticService#onBluetoothCallQualityReportReceived(
+     * BluetoothCallQualityReport)}.
+     * @param qualityReport The bluetooth call quality remote.
+     */
+    private void handleBluetoothCallQualityReport(@NonNull BluetoothCallQualityReport
+            qualityReport) {
+        Log.i(this, "handleBluetoothCallQualityReport; report=%s", qualityReport);
+        onBluetoothCallQualityReportReceived(qualityReport);
+    }
+
+    /**
+     * Handles a request from a {@link DiagnosticCall} to send a device to device message (received
+     * via {@link DiagnosticCall#sendDeviceToDeviceMessage(int, int)}.
+     * @param diagnosticCall
+     * @param message
+     * @param value
+     */
+    private void handleSendDeviceToDeviceMessage(@NonNull DiagnosticCall diagnosticCall,
+            int message, int value) {
+        String callId = diagnosticCall.getCallId();
+        try {
+            mAdapter.sendDeviceToDeviceMessage(callId, message, value);
+            Log.i(this, "handleSendDeviceToDeviceMessage: call=%s; msg=%d/%d", callId, message,
+                    value);
+        } catch (RemoteException e) {
+            Log.w(this, "handleSendDeviceToDeviceMessage: call=%s; msg=%d/%d failed %s",
+                    callId, message, value, e);
+        }
+    }
+
+    /**
+     * Handles a request from a {@link DiagnosticCall} to display an in-call diagnostic message.
+     * Originates from {@link DiagnosticCall#displayDiagnosticMessage(int, CharSequence)}.
+     * @param diagnosticCall
+     * @param messageId
+     * @param message
+     */
+    private void handleDisplayDiagnosticMessage(DiagnosticCall diagnosticCall, int messageId,
+            CharSequence message) {
+        String callId = diagnosticCall.getCallId();
+        try {
+            mAdapter.displayDiagnosticMessage(callId, messageId, message);
+            Log.i(this, "handleDisplayDiagnosticMessage: call=%s; msg=%d/%s", callId, messageId,
+                    message);
+        } catch (RemoteException e) {
+            Log.w(this, "handleDisplayDiagnosticMessage: call=%s; msg=%d/%s failed %s",
+                    callId, messageId, message, e);
+        }
+    }
+
+    /**
+     * Handles a request from a {@link DiagnosticCall} to clear a previously shown diagnostic
+     * message.
+     * Originates from {@link DiagnosticCall#clearDiagnosticMessage(int)}.
+     * @param diagnosticCall
+     * @param messageId
+     */
+    private void handleClearDiagnosticMessage(DiagnosticCall diagnosticCall, int messageId) {
+        String callId = diagnosticCall.getCallId();
+        try {
+            mAdapter.clearDiagnosticMessage(callId, messageId);
+            Log.i(this, "handleClearDiagnosticMessage: call=%s; msg=%d", callId, messageId);
+        } catch (RemoteException e) {
+            Log.w(this, "handleClearDiagnosticMessage: call=%s; msg=%d failed %s",
+                    callId, messageId, e);
+        }
+    }
+}
diff --git a/telecomm/java/android/telecom/Connection.aidl b/telecomm/java/android/telecom/Connection.aidl
new file mode 100644
index 0000000..5b40036
--- /dev/null
+++ b/telecomm/java/android/telecom/Connection.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telecom;
+
+/**
+ * {@hide}
+ */
+parcelable Connection.CallFilteringCompletionInfo;
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 942a54e..335857af8 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -29,6 +29,7 @@
 import android.app.Notification;
 import android.bluetooth.BluetoothDevice;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.content.ComponentName;
 import android.content.Intent;
 import android.hardware.camera2.CameraManager;
 import android.net.Uri;
@@ -38,7 +39,9 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.telephony.ims.ImsStreamMediaProfile;
@@ -935,6 +938,46 @@
     public static final String EVENT_RTT_AUDIO_INDICATION_CHANGED =
             "android.telecom.event.RTT_AUDIO_INDICATION_CHANGED";
 
+    /**
+     * Connection event used to signal between the telephony {@link ConnectionService} and Telecom
+     * when device to device messages are sent/received.
+     * <p>
+     * Device to device messages originating from the network are sent by telephony using
+     * {@link Connection#sendConnectionEvent(String, Bundle)} and are routed up to any active
+     * {@link CallDiagnosticService} implementation which is active.
+     * <p>
+     * Likewise, if a {@link CallDiagnosticService} sends a message using
+     * {@link DiagnosticCall#sendDeviceToDeviceMessage(int, int)}, it will be routed to telephony
+     * via {@link Connection#onCallEvent(String, Bundle)}.  The telephony stack will relay the
+     * message to the other device.
+     * @hide
+     */
+    @SystemApi
+    public static final String EVENT_DEVICE_TO_DEVICE_MESSAGE =
+            "android.telecom.event.DEVICE_TO_DEVICE_MESSAGE";
+
+    /**
+     * Sent along with {@link #EVENT_DEVICE_TO_DEVICE_MESSAGE} to indicate the device to device
+     * message type.
+     *
+     * See {@link DiagnosticCall} for more information.
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_DEVICE_TO_DEVICE_MESSAGE_TYPE =
+            "android.telecom.extra.DEVICE_TO_DEVICE_MESSAGE_TYPE";
+
+    /**
+     * Sent along with {@link #EVENT_DEVICE_TO_DEVICE_MESSAGE} to indicate the device to device
+     * message value.
+     * <p>
+     * See {@link DiagnosticCall} for more information.
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_DEVICE_TO_DEVICE_MESSAGE_VALUE =
+            "android.telecom.extra.DEVICE_TO_DEVICE_MESSAGE_VALUE";
+
     // Flag controlling whether PII is emitted into the logs
     private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
 
@@ -3379,6 +3422,121 @@
     public void handleRttUpgradeResponse(@Nullable RttTextStream rttTextStream) {}
 
     /**
+     * Information provided to a {@link Connection} upon completion of call filtering in Telecom.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final class CallFilteringCompletionInfo implements Parcelable {
+        private final boolean mIsBlocked;
+        private final boolean mIsInContacts;
+        private final CallScreeningService.CallResponse mCallResponse;
+        private final ComponentName mCallScreeningComponent;
+
+        /**
+         * Constructor for {@link CallFilteringCompletionInfo}
+         *
+         * @param isBlocked Whether any part of the call filtering process indicated that this call
+         *                  should be blocked.
+         * @param isInContacts Whether the caller is in the user's contacts.
+         * @param callResponse The instance of {@link CallScreeningService.CallResponse} provided
+         *                     by the {@link CallScreeningService} that processed this call, or
+         *                     {@code null} if no call screening service ran.
+         * @param callScreeningComponent The component of the {@link CallScreeningService}
+         *                                 that processed this call, or {@link null} if no
+         *                                 call screening service ran.
+         */
+        public CallFilteringCompletionInfo(boolean isBlocked, boolean isInContacts,
+                @Nullable CallScreeningService.CallResponse callResponse,
+                @Nullable ComponentName callScreeningComponent) {
+            mIsBlocked = isBlocked;
+            mIsInContacts = isInContacts;
+            mCallResponse = callResponse;
+            mCallScreeningComponent = callScreeningComponent;
+        }
+
+        /** @hide */
+        protected CallFilteringCompletionInfo(Parcel in) {
+            mIsBlocked = in.readByte() != 0;
+            mIsInContacts = in.readByte() != 0;
+            CallScreeningService.ParcelableCallResponse response
+                    = in.readParcelable(CallScreeningService.class.getClassLoader());
+            mCallResponse = response == null ? null : response.toCallResponse();
+            mCallScreeningComponent = in.readParcelable(ComponentName.class.getClassLoader());
+        }
+
+        @NonNull
+        public static final Creator<CallFilteringCompletionInfo> CREATOR =
+                new Creator<CallFilteringCompletionInfo>() {
+                    @Override
+                    public CallFilteringCompletionInfo createFromParcel(Parcel in) {
+                        return new CallFilteringCompletionInfo(in);
+                    }
+
+                    @Override
+                    public CallFilteringCompletionInfo[] newArray(int size) {
+                        return new CallFilteringCompletionInfo[size];
+                    }
+                };
+
+        /**
+         * @return Whether any part of the call filtering process indicated that this call should be
+         *         blocked.
+         */
+        public boolean isBlocked() {
+            return mIsBlocked;
+        }
+
+        /**
+         * @return Whether the caller is in the user's contacts.
+         */
+        public boolean isInContacts() {
+            return mIsInContacts;
+        }
+
+        /**
+         * @return The instance of {@link CallScreeningService.CallResponse} provided
+         *         by the {@link CallScreeningService} that processed this
+         *         call, or {@code null} if no call screening service ran.
+         */
+        public @Nullable CallScreeningService.CallResponse getCallResponse() {
+            return mCallResponse;
+        }
+
+        /**
+         * @return The component of the {@link CallScreeningService}
+         *         that processed this call, or {@code null} if no call screening service ran.
+         */
+        public @Nullable ComponentName getCallScreeningComponent() {
+            return mCallScreeningComponent;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public String toString() {
+            return "CallFilteringCompletionInfo{" +
+                    "mIsBlocked=" + mIsBlocked +
+                    ", mIsInContacts=" + mIsInContacts +
+                    ", mCallResponse=" + mCallResponse +
+                    ", mCallScreeningPackageName='" + mCallScreeningComponent + '\'' +
+                    '}';
+        }
+
+        /** @hide */
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeByte((byte) (mIsBlocked ? 1 : 0));
+            dest.writeByte((byte) (mIsInContacts ? 1 : 0));
+            dest.writeParcelable(mCallResponse == null ? null : mCallResponse.toParcelable(), 0);
+            dest.writeParcelable(mCallScreeningComponent, 0);
+        }
+    }
+
+    /**
      * Indicates that call filtering in Telecom is complete
      *
      * This method is called for a connection created via
@@ -3386,24 +3544,13 @@
      * Telecom, including checking the blocked number db, per-contact settings, and custom call
      * filtering apps.
      *
-     * @param isBlocked {@code true} if the call was blocked, {@code false} otherwise. If this is
-     *                  {@code true}, {@link #onDisconnect()} will be called soon after
-     *                  this is called.
-     * @param isInContacts Indicates whether the caller is in the user's contacts list.
-     * @param callScreeningResponse The response that was returned from the
-     *                              {@link CallScreeningService} that handled this call. If no
-     *                              response was received from a call screening service,
-     *                              this will be {@code null}.
-     * @param isResponseFromSystemDialer Whether {@code callScreeningResponse} was sent from the
-     *                                  system dialer. If {@code callScreeningResponse} is
-     *                                  {@code null}, this will be {@code false}.
+     * @param callFilteringCompletionInfo Info provided by Telecom on the results of call filtering.
      * @hide
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.READ_CONTACTS)
-    public void onCallFilteringCompleted(boolean isBlocked, boolean isInContacts,
-            @Nullable CallScreeningService.CallResponse callScreeningResponse,
-            boolean isResponseFromSystemDialer) { }
+    public void onCallFilteringCompleted(
+            @NonNull CallFilteringCompletionInfo callFilteringCompletionInfo) { }
 
     static String toLogSafePhoneNumber(String number) {
         // For unknown number, log empty string.
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 966ece3..c189b19 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -758,19 +758,15 @@
         }
 
         @Override
-        public void onCallFilteringCompleted(String callId, boolean isBlocked, boolean isInContacts,
-                CallScreeningService.ParcelableCallResponse callScreeningResponse,
-                boolean isResponseFromSystemDialer,
+        public void onCallFilteringCompleted(String callId,
+                Connection.CallFilteringCompletionInfo completionInfo,
                 Session.Info sessionInfo) {
             Log.startSession(sessionInfo, SESSION_CALL_FILTERING_COMPLETED);
             try {
                 SomeArgs args = SomeArgs.obtain();
                 args.arg1 = callId;
-                args.arg2 = isBlocked;
-                args.arg3 = isInContacts;
-                args.arg4 = callScreeningResponse;
-                args.arg5 = isResponseFromSystemDialer;
-                args.arg6 = Log.createSubsession();
+                args.arg2 = completionInfo;
+                args.arg3 = Log.createSubsession();
                 mHandler.obtainMessage(MSG_ON_CALL_FILTERING_COMPLETED, args).sendToTarget();
             } finally {
                 Log.endSession();
@@ -1441,16 +1437,12 @@
                 case MSG_ON_CALL_FILTERING_COMPLETED: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
-                        Log.continueSession((Session) args.arg6,
+                        Log.continueSession((Session) args.arg3,
                                 SESSION_HANDLER + SESSION_CALL_FILTERING_COMPLETED);
                         String callId = (String) args.arg1;
-                        boolean isBlocked = (boolean) args.arg2;
-                        boolean isInContacts = (boolean) args.arg3;
-                        CallScreeningService.ParcelableCallResponse callScreeningResponse =
-                                (CallScreeningService.ParcelableCallResponse) args.arg4;
-                        boolean isResponseFromSystemDialer = (boolean) args.arg5;
-                        onCallFilteringCompleted(callId, isBlocked, isInContacts,
-                                callScreeningResponse, isResponseFromSystemDialer);
+                        Connection.CallFilteringCompletionInfo completionInfo =
+                                (Connection.CallFilteringCompletionInfo) args.arg2;
+                        onCallFilteringCompleted(callId, completionInfo);
                     } finally {
                         args.recycle();
                         Log.endSession();
@@ -2466,16 +2458,12 @@
         }
     }
 
-    private void onCallFilteringCompleted(String callId, boolean isBlocked, boolean isInContacts,
-            CallScreeningService.ParcelableCallResponse callScreeningResponse,
-            boolean isResponseFromSystemDialer) {
-        Log.i(this, "onCallFilteringCompleted(%s, %b, %b, %s, %b)", callId,
-                isBlocked, isInContacts, callScreeningResponse, isResponseFromSystemDialer);
+    private void onCallFilteringCompleted(String callId, Connection.CallFilteringCompletionInfo
+            callFilteringCompletionInfo) {
+        Log.i(this, "onCallFilteringCompleted(%s, %s)", callId, callFilteringCompletionInfo);
         Connection connection = findConnectionForAction(callId, "onCallFilteringCompleted");
         if (connection != null) {
-            connection.onCallFilteringCompleted(isBlocked, isInContacts,
-                    callScreeningResponse == null ? null : callScreeningResponse.toCallResponse(),
-                    isResponseFromSystemDialer);
+            connection.onCallFilteringCompleted(callFilteringCompletionInfo);
         }
     }
 
diff --git a/telecomm/java/android/telecom/DiagnosticCall.java b/telecomm/java/android/telecom/DiagnosticCall.java
new file mode 100644
index 0000000..a495289
--- /dev/null
+++ b/telecomm/java/android/telecom/DiagnosticCall.java
@@ -0,0 +1,381 @@
+/*
+ * 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.telecom;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.telephony.Annotation;
+import android.telephony.CallQuality;
+import android.telephony.ims.ImsReasonInfo;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A {@link DiagnosticCall} provides a way for a {@link CallDiagnosticService} to receive diagnostic
+ * information about a mobile call on the device.  The {@link CallDiagnosticService} can generate
+ * mid-call diagnostic messages using the {@link #displayDiagnosticMessage(int, CharSequence)} API
+ * which provides the user with valuable information about conditions impacting their call and
+ * corrective actions.  For example, if the {@link CallDiagnosticService} determines that conditions
+ * on the call are degrading, it can inform the user that the call may soon drop and that they
+ * can try using a different calling method (e.g. VOIP or WIFI).
+ * @hide
+ */
+@SystemApi
+public abstract class DiagnosticCall {
+
+    /**
+     * @hide
+     */
+    public interface Listener {
+        void onSendDeviceToDeviceMessage(DiagnosticCall diagnosticCall, int message, int value);
+        void onDisplayDiagnosticMessage(DiagnosticCall diagnosticCall, int messageId,
+                CharSequence message);
+        void onClearDiagnosticMessage(DiagnosticCall diagnosticCall, int messageId);
+    }
+
+    /**
+     * Device to device message sent via {@link #sendDeviceToDeviceMessage(int, int)} (received via
+     * {@link #onReceiveDeviceToDeviceMessage(int, int)}) which communicates the radio access type
+     * used for the current call.  Based loosely on the
+     * {@link android.telephony.TelephonyManager#getNetworkType(int)} for the call, provides a
+     * high level summary of the call radio access type.
+     * <p>
+     * Valid values:
+     * <UL>
+     *     <LI>{@link #NETWORK_TYPE_LTE}</LI>
+     *     <LI>{@link #NETWORK_TYPE_IWLAN}</LI>
+     *     <LI>{@link #NETWORK_TYPE_NR}</LI>
+     * </UL>
+     */
+    public static final int MESSAGE_CALL_NETWORK_TYPE = 1;
+
+    /**
+     * Device to device message sent via {@link #sendDeviceToDeviceMessage(int, int)} (received via
+     * {@link #onReceiveDeviceToDeviceMessage(int, int)}) which communicates the call audio codec
+     * used for the current call.  Based loosely on the {@link Connection#EXTRA_AUDIO_CODEC} for a
+     * call.
+     * <p>
+     * Valid values:
+     * <UL>
+     *     <LI>{@link #AUDIO_CODEC_EVS}</LI>
+     *     <LI>{@link #AUDIO_CODEC_AMR_WB}</LI>
+     *     <LI>{@link #AUDIO_CODEC_AMR_NB}</LI>
+     * </UL>
+     */
+    public static final int MESSAGE_CALL_AUDIO_CODEC = 2;
+
+    /**
+     * Device to device message sent via {@link #sendDeviceToDeviceMessage(int, int)} (received via
+     * {@link #onReceiveDeviceToDeviceMessage(int, int)}) which communicates the battery state of
+     * the device.  Will typically mirror battery state reported via intents such as
+     * {@link android.content.Intent#ACTION_BATTERY_LOW}.
+     * <p>
+     * Valid values:
+     * <UL>
+     *     <LI>{@link #BATTERY_STATE_LOW}</LI>
+     *     <LI>{@link #BATTERY_STATE_GOOD}</LI>
+     *     <LI>{@link #BATTERY_STATE_CHARGING}</LI>
+     * </UL>
+     */
+    public static final int MESSAGE_DEVICE_BATTERY_STATE = 3;
+
+    /**
+     * Device to device message sent via {@link #sendDeviceToDeviceMessage(int, int)} (received via
+     * {@link #onReceiveDeviceToDeviceMessage(int, int)}) which communicates the overall network
+     * coverage as it pertains to the current call.  A {@link CallDiagnosticService} should signal
+     * poor coverage if the network coverage reaches a level where there is a high probability of
+     * the call dropping as a result.
+     * <p>
+     * Valid values:
+     * <UL>
+     *     <LI>{@link #COVERAGE_POOR}</LI>
+     *     <LI>{@link #COVERAGE_GOOD}</LI>
+     * </UL>
+     */
+    public static final int MESSAGE_DEVICE_NETWORK_COVERAGE = 4;
+
+    /**@hide*/
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "MESSAGE_", value = {
+            MESSAGE_CALL_NETWORK_TYPE,
+            MESSAGE_CALL_AUDIO_CODEC,
+            MESSAGE_DEVICE_BATTERY_STATE,
+            MESSAGE_DEVICE_NETWORK_COVERAGE
+    })
+    public @interface MessageType {}
+
+    /**
+     * Used with {@link #MESSAGE_CALL_NETWORK_TYPE} to indicate an LTE network is being used for the
+     * call.
+     */
+    public static final int NETWORK_TYPE_LTE = 1;
+
+    /**
+     * Used with {@link #MESSAGE_CALL_NETWORK_TYPE} to indicate WIFI calling is in use for the call.
+     */
+    public static final int NETWORK_TYPE_IWLAN = 2;
+
+    /**
+     * Used with {@link #MESSAGE_CALL_NETWORK_TYPE} to indicate a 5G NR (new radio) network is in
+     * used for the call.
+     */
+    public static final int NETWORK_TYPE_NR = 3;
+
+    /**
+     * Used with {@link #MESSAGE_CALL_AUDIO_CODEC} to indicate call audio is using the
+     * Enhanced Voice Services (EVS) codec for the call.
+     */
+    public static final int AUDIO_CODEC_EVS = 1;
+
+    /**
+     * Used with {@link #MESSAGE_CALL_AUDIO_CODEC} to indicate call audio is using the AMR
+     * (adaptive multi-rate) WB (wide band) audio codec.
+     */
+    public static final int AUDIO_CODEC_AMR_WB = 2;
+
+    /**
+     * Used with {@link #MESSAGE_CALL_AUDIO_CODEC} to indicate call audio is using the AMR
+     * (adaptive multi-rate) NB (narrow band) audio codec.
+     */
+    public static final int AUDIO_CODEC_AMR_NB = 3;
+
+    /**
+     * Used with {@link #MESSAGE_DEVICE_BATTERY_STATE} to indicate that the battery is low.
+     */
+    public static final int BATTERY_STATE_LOW = 1;
+
+    /**
+     * Used with {@link #MESSAGE_DEVICE_BATTERY_STATE} to indicate that the battery is not low.
+     */
+    public static final int BATTERY_STATE_GOOD = 2;
+
+    /**
+     * Used with {@link #MESSAGE_DEVICE_BATTERY_STATE} to indicate that the battery is charging.
+     */
+    public static final int BATTERY_STATE_CHARGING = 3;
+
+    /**
+     * Used with {@link #MESSAGE_DEVICE_NETWORK_COVERAGE} to indicate that the coverage is poor.
+     */
+    public static final int COVERAGE_POOR = 1;
+
+    /**
+     * Used with {@link #MESSAGE_DEVICE_NETWORK_COVERAGE} to indicate that the coverage is good.
+     */
+    public static final int COVERAGE_GOOD = 2;
+
+    private Listener mListener;
+    private String mCallId;
+    private Call.Details mCallDetails;
+
+    /**
+     * @hide
+     */
+    public void setListener(@NonNull Listener listener) {
+        mListener = listener;
+    }
+
+    /**
+     * Sets the call ID for this {@link DiagnosticCall}.
+     * @param callId
+     * @hide
+     */
+    public void setCallId(@NonNull String callId) {
+        mCallId = callId;
+    }
+
+    /**
+     * @return the Telecom call ID for this {@link DiagnosticCall}.
+     * @hide
+     */
+    public @NonNull String getCallId() {
+        return mCallId;
+    }
+
+    /**
+     * Returns the latest {@link Call.Details} associated with this {@link DiagnosticCall} as
+     * reported by {@link #onCallDetailsChanged(Call.Details)}.
+     * @return The latest {@link Call.Details}.
+     */
+    public @NonNull Call.Details getCallDetails() {
+        return mCallDetails;
+    }
+
+    /**
+     * Telecom calls this method when the details of a call changes.
+     */
+    public abstract void onCallDetailsChanged(@NonNull android.telecom.Call.Details details);
+
+    /**
+     * The {@link CallDiagnosticService} implements this method to handle messages received via
+     * device to device communication.
+     * <p>
+     * See {@link #sendDeviceToDeviceMessage(int, int)} for background on device to device
+     * communication.
+     * <p>
+     * The underlying device to device communication protocol assumes that where there the two
+     * devices communicating are using a different version of the protocol, messages the recipient
+     * are not aware of are silently discarded.  This means an older client talking to a new client
+     * will not receive newer messages and values sent by the new client.
+     */
+    public abstract void onReceiveDeviceToDeviceMessage(
+            @MessageType int message,
+            int value);
+
+    /**
+     * Sends a device to device message to the device on the other end of this call.
+     * <p>
+     * Device to device communication is an Android platform feature which supports low bandwidth
+     * communication between Android devices while they are in a call.  The device to device
+     * communication leverages DTMF tones or RTP header extensions to pass messages.  The
+     * messages are unacknowledged and sent in a best-effort manner.  The protocols assume that the
+     * nature of the message are informational only and are used only to convey basic state
+     * information between devices.
+     * <p>
+     * Device to device messages are intentional simplifications of more rich indicators in the
+     * platform due to the extreme bandwidth constraints inherent with underlying device to device
+     * communication transports used by the telephony framework.  Device to device communication is
+     * either accomplished by adding RFC8285 compliant RTP header extensions to the audio packets
+     * for a call, or using the DTMF digits A-D as a communication pathway.  Signalling requirements
+     * for DTMF digits place a significant limitation on the amount of information which can be
+     * communicated during a call.
+     * <p>
+     * Allowed message types and values are:
+     * <ul>
+     *     <li>{@link #MESSAGE_CALL_NETWORK_TYPE}
+     *         <ul>
+     *             <li>{@link #NETWORK_TYPE_LTE}</li>
+     *             <li>{@link #NETWORK_TYPE_IWLAN}</li>
+     *             <li>{@link #NETWORK_TYPE_NR}</li>
+     *         </ul>
+     *     </li>
+     *     <li>{@link #MESSAGE_CALL_AUDIO_CODEC}
+     *         <ul>
+     *             <li>{@link #AUDIO_CODEC_EVS}</li>
+     *             <li>{@link #AUDIO_CODEC_AMR_WB}</li>
+     *             <li>{@link #AUDIO_CODEC_AMR_NB}</li>
+     *         </ul>
+     *     </li>
+     *     <li>{@link #MESSAGE_DEVICE_BATTERY_STATE}
+     *         <ul>
+     *             <li>{@link #BATTERY_STATE_LOW}</li>
+     *             <li>{@link #BATTERY_STATE_GOOD}</li>
+     *             <li>{@link #BATTERY_STATE_CHARGING}</li>
+     *         </ul>
+     *     </li>
+     *     <li>{@link #MESSAGE_DEVICE_NETWORK_COVERAGE}
+     *         <ul>
+     *             <li>{@link #COVERAGE_POOR}</li>
+     *             <li>{@link #COVERAGE_GOOD}</li>
+     *         </ul>
+     *     </li>
+     * </ul>
+     * @param message The message type to send.
+     * @param value The message value corresponding to the type.
+     */
+    public final void sendDeviceToDeviceMessage(int message, int value) {
+        if (mListener != null) {
+            mListener.onSendDeviceToDeviceMessage(this, message, value);
+        }
+    }
+
+    /**
+     * Telecom calls this method when a GSM or CDMA call disconnects.
+     * The CallDiagnosticService can return a human readable disconnect message which will be passed
+     * to the Dialer app as the {@link DisconnectCause#getDescription()}.  A dialer app typically
+     * shows this message at the termination of the call.  If {@code null} is returned, the
+     * disconnect message generated by the telephony stack will be shown instead.
+     * <p>
+     * @param disconnectCause the disconnect cause for the call.
+     * @param preciseDisconnectCause the precise disconnect cause for the call.
+     * @return the disconnect message to use in place of the default Telephony message, or
+     * {@code null} if the default message will not be overridden.
+     */
+    // TODO: Wire in Telephony support for this.
+    public abstract @Nullable CharSequence onCallDisconnected(
+            @Annotation.DisconnectCauses int disconnectCause,
+            @Annotation.PreciseDisconnectCauses int preciseDisconnectCause);
+
+    /**
+     * Telecom calls this method when an IMS call disconnects and Telephony has already
+     * provided the disconnect reason info and disconnect message for the call.  The
+     * {@link CallDiagnosticService} can intercept the raw IMS disconnect reason at this point and
+     * combine it with other call diagnostic information it is aware of to override the disconnect
+     * call message if desired.
+     *
+     * @param disconnectReason The {@link ImsReasonInfo} associated with the call disconnection.
+     * @return A user-readable call disconnect message to use in place of the platform-generated
+     * disconnect message, or {@code null} if the disconnect message should not be overridden.
+     */
+    // TODO: Wire in Telephony support for this.
+    public abstract @Nullable CharSequence onCallDisconnected(
+            @NonNull ImsReasonInfo disconnectReason);
+
+    /**
+     * Telecom calls this method when a {@link CallQuality} report is received from the telephony
+     * stack for a call.
+     * @param callQuality The call quality report for this call.
+     */
+    public abstract void onCallQualityReceived(@NonNull CallQuality callQuality);
+
+     /**
+      * Signals the active default dialer app to display a call diagnostic message.  This can be
+      * used to report problems encountered during the span of a call.
+      * <p>
+      * The {@link CallDiagnosticService} provides a unique client-specific identifier used to
+      * identify the specific diagnostic message type.
+      * <p>
+      * The {@link CallDiagnosticService} should call {@link #clearDiagnosticMessage(int)} when the
+      * diagnostic condition has cleared.
+      * @param messageId the unique message identifier.
+      * @param message a human-readable, localized message to be shown to the user indicating a
+      *                call issue which has occurred, along with potential mitigating actions.
+     */
+    public final void displayDiagnosticMessage(int messageId, @NonNull
+            CharSequence message) {
+        if (mListener != null) {
+            mListener.onDisplayDiagnosticMessage(this, messageId, message);
+        }
+    }
+
+    /**
+     * Signals to the active default dialer that the diagnostic message previously signalled using
+     * {@link #displayDiagnosticMessage(int, CharSequence)} with the specified messageId is no
+     * longer applicable (e.g. service has improved, for example.
+     * @param messageId the message identifier for a message previously shown via
+     *                  {@link #displayDiagnosticMessage(int, CharSequence)}.
+     */
+    public final void clearDiagnosticMessage(int messageId) {
+        if (mListener != null) {
+            mListener.onClearDiagnosticMessage(this, messageId);
+        }
+    }
+
+    /**
+     * Called by the {@link CallDiagnosticService} to update the call details for this
+     * {@link DiagnosticCall} based on an update received from Telecom.
+     * @param newDetails the new call details.
+     * @hide
+     */
+    public void handleCallUpdated(@NonNull Call.Details newDetails) {
+        mCallDetails = newDetails;
+        onCallDetailsChanged(newDetails);
+    }
+}
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 5cf8de8..f20ee7e 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -138,6 +138,24 @@
  *     }
  * }
  * }
+ *
+ * </pre>
+ * <p id="companionInCallService">
+ * <h3>Access to InCallService for Wearable Devices</h3>
+ * <ol>
+ * If your app is a third-party companion app and wants to access InCallService APIs, what your
+ * app could do are:
+ * <p>
+ *   <ol>
+ *     <li> Declare MANAGE_ONGOING_CALLS permission in your manifest
+ *     <li> Associate with a physical wearable device via the
+ *          {@link android.companion.CompanionDeviceManager} API as a companion app. See:
+ *          https://developer.android.com/guide/topics/connectivity/companion-device-pairing
+ *     <li> Implement this InCallService with BIND_INCALL_SERVICE permission
+ *   </ol>
+ * </ol>
+ * <p>
+ *
  * </pre>
  * <p id="incomingCallNotification">
  * <h3>Showing the Incoming Call Notification</h3>
diff --git a/telecomm/java/android/telecom/Log.java b/telecomm/java/android/telecom/Log.java
index 2a4fdcb..922eddb 100644
--- a/telecomm/java/android/telecom/Log.java
+++ b/telecomm/java/android/telecom/Log.java
@@ -522,7 +522,7 @@
             return "";
         }
         return Arrays.stream(packageName.split("\\."))
-                .map(s -> s.substring(0,1))
+                .map(s -> s.length() == 0 ? "" : s.substring(0, 1))
                 .collect(Collectors.joining(""));
     }
 }
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index 6c6097a..7a6fddb 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -1202,27 +1202,18 @@
     /**
      * Notifies this {@link RemoteConnection} that call filtering has completed, as well as
      * the results of a contacts lookup for the remote party.
-     * @param isBlocked Whether call filtering indicates that the call should be blocked
-     * @param isInContacts Whether the remote party is in the user's contacts
-     * @param callScreeningResponse The response that was returned from the
-     *                              {@link CallScreeningService} that handled this call. If no
-     *                              response was received from a call screening service,
-     *                              this will be {@code null}.
-     * @param isResponseFromSystemDialer Whether {@code callScreeningResponse} was sent from the
-     *                                  system dialer. If {@code callScreeningResponse} is
-     *                                  {@code null}, this will be {@code false}.
+     *
+     * @param completionInfo Info provided by Telecom on the results of call filtering.
      * @hide
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.READ_CONTACTS)
-    public void onCallFilteringCompleted(boolean isBlocked, boolean isInContacts,
-            @Nullable CallScreeningService.CallResponse callScreeningResponse,
-            boolean isResponseFromSystemDialer) {
+    public void onCallFilteringCompleted(
+            @NonNull Connection.CallFilteringCompletionInfo completionInfo) {
         Log.startSession("RC.oCFC", getActiveOwnerInfo());
         try {
             if (mConnected) {
-                mConnectionService.onCallFilteringCompleted(mConnectionId, isBlocked, isInContacts,
-                        callScreeningResponse.toParcelable(), isResponseFromSystemDialer,
+                mConnectionService.onCallFilteringCompleted(mConnectionId, completionInfo,
                         null /*Session.Info*/);
             }
         } catch (RemoteException ignored) {
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 472d639..17749e8 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1702,22 +1702,22 @@
     }
 
     /**
-     * Returns whether the caller has {@link InCallService} access for companion apps.
-     *
-     * A companion app is an app associated with a physical wearable device via the
-     * {@link android.companion.CompanionDeviceManager} API.
+     * Returns whether the caller has {@link android.Manifest.permission#MANAGE_ONGOING_CALLS}
+     * permission. The permission can be obtained by associating with a physical wearable device
+     * via the {@link android.companion.CompanionDeviceManager} API as a companion app. If the
+     * caller app has the permission, it has {@link InCallService} access to manage ongoing calls.
      *
      * @return {@code true} if the caller has {@link InCallService} access for
      *      companion app; {@code false} otherwise.
      */
-    public boolean hasCompanionInCallServiceAccess() {
+    public boolean hasManageOngoingCallsPermission() {
         ITelecomService service = getTelecomService();
         if (service != null) {
             try {
-                return service.hasCompanionInCallServiceAccess(
+                return service.hasManageOngoingCallsPermission(
                         mContext.getOpPackageName());
             } catch (RemoteException e) {
-                Log.e(TAG, "RemoteException calling hasCompanionInCallServiceAccess().", e);
+                Log.e(TAG, "RemoteException calling hasManageOngoingCallsPermission().", e);
                 if (!isSystemProcess()) {
                     e.rethrowAsRuntimeException();
                 }
diff --git a/telecomm/java/com/android/internal/telecom/ICallDiagnosticService.aidl b/telecomm/java/com/android/internal/telecom/ICallDiagnosticService.aidl
new file mode 100644
index 0000000..65b4d19
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecom/ICallDiagnosticService.aidl
@@ -0,0 +1,37 @@
+/*
+ * 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.telecom;
+
+import android.telecom.BluetoothCallQualityReport;
+import android.telecom.CallAudioState;
+import android.telecom.ParcelableCall;
+import com.android.internal.telecom.ICallDiagnosticServiceAdapter;
+
+/**
+ * Internal remote interface for a call diagnostic service.
+ * @see android.telecom.CallDiagnosticService
+ * @hide
+ */
+oneway interface ICallDiagnosticService {
+    void setAdapter(in ICallDiagnosticServiceAdapter adapter);
+    void initializeDiagnosticCall(in ParcelableCall call);
+    void updateCall(in ParcelableCall call);
+    void updateCallAudioState(in CallAudioState callAudioState);
+    void removeDiagnosticCall(in String callId);
+    void receiveDeviceToDeviceMessage(in String callId, int message, int value);
+    void receiveBluetoothCallQualityReport(in BluetoothCallQualityReport qualityReport);
+}
diff --git a/telecomm/java/com/android/internal/telecom/ICallDiagnosticServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/ICallDiagnosticServiceAdapter.aidl
new file mode 100644
index 0000000..92eec2a
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecom/ICallDiagnosticServiceAdapter.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 com.android.internal.telecom;
+
+import android.telecom.CallAudioState;
+import android.telecom.ParcelableCall;
+
+/**
+ * Remote interface for messages from the CallDiagnosticService to the platform.
+ * @see android.telecom.CallDiagnosticService
+ * @hide
+ */
+oneway interface ICallDiagnosticServiceAdapter {
+    void displayDiagnosticMessage(in String callId, int messageId, in CharSequence message);
+    void clearDiagnosticMessage(in String callId, int messageId);
+    void sendDeviceToDeviceMessage(in String callId, int message, int value);
+    void overrideDisconnectMessage(in String callId, in CharSequence message);
+}
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index 7599e18..d72f8aa 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -20,7 +20,7 @@
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.telecom.CallAudioState;
-import android.telecom.CallScreeningService;
+import android.telecom.Connection;
 import android.telecom.ConnectionRequest;
 import android.telecom.Logging.Session;
 import android.telecom.PhoneAccountHandle;
@@ -119,9 +119,9 @@
 
     void sendCallEvent(String callId, String event, in Bundle extras, in Session.Info sessionInfo);
 
-    void onCallFilteringCompleted(String callId, boolean isBlocked, boolean isInContacts,
-            in CallScreeningService.ParcelableCallResponse callScreeningResponse,
-            boolean isResponseFromSystemDialer, in Session.Info sessionInfo);
+    void onCallFilteringCompleted(String callId,
+            in Connection.CallFilteringCompletionInfo completionInfo,
+            in Session.Info sessionInfo);
 
     void onExtrasChanged(String callId, in Bundle extras, in Session.Info sessionInfo);
 
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 88ef1b0..78283fa 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -179,9 +179,9 @@
     boolean isInCall(String callingPackage, String callingFeatureId);
 
     /**
-     * @see TelecomServiceImpl#hasCompanionInCallServiceAccess
+     * @see TelecomServiceImpl#hasManageOngoingCallsPermission
      */
-    boolean hasCompanionInCallServiceAccess(String callingPackage);
+    boolean hasManageOngoingCallsPermission(String callingPackage);
 
     /**
      * @see TelecomServiceImpl#isInManagedCall
@@ -353,4 +353,8 @@
      */
     void setTestDefaultDialer(in String packageName);
 
+    /**
+     * @see TelecomServiceImpl#setTestCallDiagnosticService
+     */
+    void setTestCallDiagnosticService(in String packageName);
 }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 3d43d03..b52f4919 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -33,7 +33,11 @@
 import android.service.carrier.CarrierService;
 import android.telecom.TelecomManager;
 import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.ImsRegistrationAttributes;
 import android.telephony.ims.ImsSsData;
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.feature.MmTelFeature;
+import android.telephony.ims.feature.RcsFeature;
 
 import com.android.internal.telephony.ICarrierConfigLoader;
 import com.android.telephony.Rlog;
@@ -1717,8 +1721,14 @@
      * Configs used for APN setup.
      */
     public static final class Apn {
-        /** Prefix of all Apn.KEY_* constants. */
-        private static final String KEY_PREFIX = "apn.";
+        /**
+         * Prefix of all Apn.KEY_* constants.
+         *
+         * @deprecated Since KEY_PREFIX is unnecessary to public, it will modify to private
+         * next android generation.
+         */
+        @Deprecated
+        public static final String KEY_PREFIX = "apn.";
 
         /** IPv4 internet protocol */
         public static final String PROTOCOL_IPV4 = "IP";
@@ -3666,14 +3676,13 @@
         /** Prefix of all ImsServiceEntitlement.KEY_* constants. */
         public static final String KEY_PREFIX = "imsserviceentitlement.";
 
-
         /** The address of the entitlement configuration server. */
-        public static final String KEY_AES_URL_STRING = KEY_PREFIX + "aes_url_string";
-
+        public static final String KEY_ENTITLEMENT_SERVER_URL_STRING =
+                KEY_PREFIX + "entitlement_server_url_string";
 
         private static PersistableBundle getDefaults() {
             PersistableBundle defaults = new PersistableBundle();
-            defaults.putString(KEY_AES_URL_STRING, "");
+            defaults.putString(KEY_ENTITLEMENT_SERVER_URL_STRING, "");
             return defaults;
         }
     }
@@ -4001,6 +4010,43 @@
                 KEY_PREFIX + "enable_presence_publish_bool";
 
         /**
+         * Each string in this array contains a mapping between the service-id and version portion
+         * of the service-description element and the associated IMS feature tag(s) that are
+         * associated with each element (see RCC.07 Table 7).
+         * <p>
+         * Each string contains 3 parts, which define the mapping between service-description and
+         * feature tag(s) that must be present in the IMS REGISTER for the RCS service to be
+         * published as part of the RCS PUBLISH procedure:
+         * [service-id]|[version]|[desc]|[feature_tag];[feature_tag];...
+         * <ul>
+         *   <li>[service-id]: the service-id element associated with the RCS capability.</li>
+         *   <li>[version]: The version element associated with that service-id</li>
+         *   <li>[desc]: The optional desecription element associated with that service-id</li>
+         *   <li>[feature_tag];[feature_tag]: The list of all feature tags associated with this
+         *       capability that MUST ALL be present in the IMS registration for this this
+         *       capability to be published to the network.</li>
+         * </ul>
+         * <p>
+         * Features managed by the framework will be considered capable when the ImsService reports
+         * that those services are capable via the
+         * {@link MmTelFeature#notifyCapabilitiesStatusChanged(MmTelFeature.MmTelCapabilities)} or
+         * {@link RcsFeature#notifyCapabilitiesStatusChanged(RcsFeature.RcsImsCapabilities)} APIs.
+         * For RCS services not managed by the framework, the capability of these services are
+         * determined by looking at the feature tags associated with the IMS registration using the
+         * {@link ImsRegistrationAttributes} API and mapping them to the service-description map.
+         * <p>
+         * The framework contains a default value of this key, which is based off of RCC.07
+         * specification. Capabilities based of carrier extensions may be added to this list on a
+         * carrier-by-carrier basis as required in order to support additional services in the
+         * PUBLISH. If this list contains a service-id and version that overlaps with the default,
+         * it will override the framework default.
+         * @hide
+         */
+        @SystemApi
+        public static final String KEY_PUBLISH_SERVICE_DESC_FEATURE_TAG_MAP_OVERRIDE_STRING_ARRAY =
+                KEY_PREFIX + "publish_service_desc_feature_tag_map_override_string_array";
+
+        /**
          * Flag indicating whether or not this carrier supports the exchange of phone numbers with
          * the carrier's RCS presence server in order to retrieve the RCS capabilities of requested
          * contacts used in the RCS User Capability Exchange (UCE) procedure. See RCC.71, section 3
@@ -4059,6 +4105,8 @@
             defaults.putInt(KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT, 4000);
             defaults.putBoolean(KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, false);
             defaults.putBoolean(KEY_ENABLE_PRESENCE_PUBLISH_BOOL, false);
+            defaults.putStringArray(KEY_PUBLISH_SERVICE_DESC_FEATURE_TAG_MAP_OVERRIDE_STRING_ARRAY,
+                    new String[] {});
             defaults.putBoolean(KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL, false);
             defaults.putBoolean(KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL, false);
             defaults.putBoolean(KEY_ENABLE_PRESENCE_GROUP_SUBSCRIBE_BOOL, true);
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index 706e3cb..a78f813 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -371,6 +371,7 @@
      * Get the 5G NR connection state.
      *
      * @return the 5G NR connection state.
+     * @hide
      */
     public @NRState int getNrState() {
         return mNrState;
diff --git a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
index af67ed2..fe7e5976 100644
--- a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
+++ b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
@@ -187,7 +187,7 @@
         return mIsSystemThresholdReportingRequestedWhileIdle;
     }
 
-    /*
+    /**
      * @return the live token of the request
      *
      * @hide
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 1473b7a..cf4e677 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -891,6 +891,14 @@
     public static final String PROFILE_CLASS = SimInfo.COLUMN_PROFILE_CLASS;
 
     /**
+     * TelephonyProvider column name for VoIMS opt-in status.
+     *
+     * <P>Type: INTEGER (int)</P>
+     * @hide
+     */
+    public static final String VOIMS_OPT_IN_STATUS = SimInfo.COLUMN_VOIMS_OPT_IN_STATUS;
+
+    /**
      * Profile class of the subscription
      * @hide
      */
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f64f428..b46440d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -29,6 +29,7 @@
 import android.annotation.LongDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
@@ -8579,6 +8580,9 @@
      */
     @Deprecated
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(
+            enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported",
+            value = TelephonyManager.CAPABILITY_ALLOWED_NETWORK_TYPES_USED)
     @SystemApi
     public boolean setAllowedNetworkTypes(@NetworkTypeBitMask long allowedNetworkTypes) {
         try {
@@ -8670,6 +8674,9 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(
+            enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported",
+            value = TelephonyManager.CAPABILITY_ALLOWED_NETWORK_TYPES_USED)
     public void setAllowedNetworkTypesForReason(@AllowedNetworkTypesReason int reason,
             @NetworkTypeBitMask long allowedNetworkTypes) {
         if (!isValidAllowedNetworkTypesReason(reason)) {
@@ -8708,6 +8715,9 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(
+            enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported",
+            value = TelephonyManager.CAPABILITY_ALLOWED_NETWORK_TYPES_USED)
     public @NetworkTypeBitMask long getAllowedNetworkTypesForReason(
             @AllowedNetworkTypesReason int reason) {
         if (!isValidAllowedNetworkTypesReason(reason)) {
@@ -9119,18 +9129,11 @@
      */
     public static final int CALL_COMPOSER_STATUS_ON = 1;
 
-    /**
-     * Call composer status indicating that sending/receiving pictures is disabled.
-     * All other attachments are still enabled in this state.
-     */
-    public static final int CALL_COMPOSER_STATUS_ON_NO_PICTURES = 2;
-
     /** @hide */
     @IntDef(prefix = {"CALL_COMPOSER_STATUS_"},
             value = {
                 CALL_COMPOSER_STATUS_ON,
                 CALL_COMPOSER_STATUS_OFF,
-                CALL_COMPOSER_STATUS_ON_NO_PICTURES,
             })
     public @interface CallComposerStatus {}
 
@@ -9138,9 +9141,8 @@
      * Set the user-set status for enriched calling with call composer.
      *
      * @param status user-set status for enriched calling with call composer;
-     *               it must be any of {@link #CALL_COMPOSER_STATUS_ON}
-     *               {@link #CALL_COMPOSER_STATUS_OFF},
-     *               or {@link #CALL_COMPOSER_STATUS_ON_NO_PICTURES}
+     *               it must be either {@link #CALL_COMPOSER_STATUS_ON} or
+     *               {@link #CALL_COMPOSER_STATUS_OFF}.
      *
      * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
      * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
@@ -9150,7 +9152,7 @@
      */
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public void setCallComposerStatus(@CallComposerStatus int status) {
-        if (status > CALL_COMPOSER_STATUS_ON_NO_PICTURES
+        if (status > CALL_COMPOSER_STATUS_ON
                 || status < CALL_COMPOSER_STATUS_OFF) {
             throw new IllegalArgumentException("requested status is invalid");
         }
@@ -9173,9 +9175,8 @@
      *
      * @throws SecurityException if the caller does not have the permission.
      *
-     * @return the user-set status for enriched calling with call composer, any of
-     * {@link #CALL_COMPOSER_STATUS_ON}, {@link #CALL_COMPOSER_STATUS_OFF}, or
-     * {@link #CALL_COMPOSER_STATUS_ON_NO_PICTURES}.
+     * @return the user-set status for enriched calling with call composer, either of
+     * {@link #CALL_COMPOSER_STATUS_ON} or {@link #CALL_COMPOSER_STATUS_OFF}.
      */
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public @CallComposerStatus int getCallComposerStatus() {
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index 6fda2e1..0ab679f 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -866,6 +866,19 @@
     public static final int KEY_VOICE_OVER_WIFI_ENTITLEMENT_ID = 67;
 
     /**
+     * An integer key representing the voice over IMS opt-in provisioning status for the
+     * associated subscription. Determines whether the user can see for voice services over
+     * IMS.
+     * <p>
+     * Use {@link #PROVISIONING_VALUE_ENABLED} to enable VoIMS provisioning and
+     * {@link #PROVISIONING_VALUE_DISABLED} to disable VoIMS  provisioning.
+     * @see #setProvisioningIntValue(int, int)
+     * @see #getProvisioningIntValue(int)
+     * @hide
+     */
+    public static final int KEY_VOIMS_OPT_IN_STATUS = 68;
+
+    /**
      * Callback for IMS provisioning changes.
      */
     public static class Callback {
diff --git a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
index 5eb75e7..bdf628b 100644
--- a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
+++ b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
@@ -21,6 +21,7 @@
 import android.annotation.StringDef;
 import android.annotation.SystemApi;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -39,6 +40,15 @@
 public final class RcsContactPresenceTuple implements Parcelable {
 
     /**
+     * The service ID used to indicate that service discovery via presence is available.
+     * <p>
+     * See RCC.07 v5.0 specification for more information.
+     * @hide
+     */
+    public static final String SERVICE_ID_PRESENCE =
+            "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcse.dp";
+
+    /**
      * The service ID used to indicate that MMTEL service is available.
      * <p>
      * See the GSMA RCC.07 specification for more information.
@@ -329,6 +339,13 @@
         public @NonNull @DuplexMode List<String> getUnsupportedDuplexModes() {
             return Collections.unmodifiableList(mUnsupportedDuplexModeList);
         }
+
+        @Override
+        public String toString() {
+            return "servCaps{" + "a=" + mIsAudioCapable + ", v=" + mIsVideoCapable
+                    + ", supported=" + mSupportedDuplexModeList + ", unsupported="
+                    + mUnsupportedDuplexModeList + '}';
+        }
     }
 
     /**
@@ -487,4 +504,36 @@
     public @Nullable ServiceCapabilities getServiceCapabilities() {
         return mServiceCapabilities;
     }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder("{");
+        if (Build.IS_ENG) {
+            builder.append("u=");
+            builder.append(mContactUri);
+        } else {
+            builder.append("u=");
+            builder.append(mContactUri != null ? "XXX" : "null");
+        }
+        builder.append(", id=");
+        builder.append(mServiceId);
+        builder.append(", v=");
+        builder.append(mServiceVersion);
+        builder.append(", s=");
+        builder.append(mStatus);
+        if (mTimestamp != null) {
+            builder.append(", timestamp=");
+            builder.append(mTimestamp);
+        }
+        if (mServiceDescription != null) {
+            builder.append(", servDesc=");
+            builder.append(mServiceDescription);
+        }
+        if (mServiceCapabilities != null) {
+            builder.append(", servCaps=");
+            builder.append(mServiceCapabilities);
+        }
+        builder.append("}");
+        return builder.toString();
+    }
 }
diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
index fe85502..9299fed 100644
--- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java
+++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
@@ -21,6 +21,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -344,4 +345,39 @@
     public @NonNull Uri getContactUri() {
         return mContactUri;
     }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder("RcsContactUceCapability");
+        if (mCapabilityMechanism == CAPABILITY_MECHANISM_PRESENCE) {
+            builder.append("(presence) {");
+        } else if (mCapabilityMechanism == CAPABILITY_MECHANISM_OPTIONS) {
+            builder.append("(options) {");
+        } else {
+            builder.append("(?) {");
+        }
+        if (Build.IS_ENG) {
+            builder.append("uri=");
+            builder.append(mContactUri);
+        } else {
+            builder.append("uri (isNull)=");
+            builder.append(mContactUri != null ? "XXX" : "null");
+        }
+        builder.append(", sourceType=");
+        builder.append(mSourceType);
+        builder.append(", requestResult=");
+        builder.append(mRequestResult);
+
+        if (mCapabilityMechanism == CAPABILITY_MECHANISM_PRESENCE) {
+            builder.append(", presenceTuples={");
+            builder.append(mPresenceTuples);
+            builder.append("}");
+        } else if (mCapabilityMechanism == CAPABILITY_MECHANISM_OPTIONS) {
+            builder.append(", featureTags={");
+            builder.append(mFeatureTags);
+            builder.append("}");
+        }
+
+        return builder.toString();
+    }
 }
diff --git a/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl b/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl
index 5eee389..1b5e560 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl
@@ -47,4 +47,6 @@
     void removeRcsConfigCallback(IRcsConfigCallback c);
     void triggerRcsReconfiguration();
     void setRcsClientConfiguration(in RcsClientConfiguration rcc);
+    void notifyIntImsConfigChanged(int item, int value);
+    void notifyStringImsConfigChanged(int item, String value);
 }
diff --git a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java
index 4967e5d..6295548 100644
--- a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java
+++ b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java
@@ -25,7 +25,6 @@
 import android.telephony.ims.RcsUceAdapter;
 import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.feature.RcsFeature;
-import android.util.Log;
 
 import java.util.List;
 
@@ -44,30 +43,12 @@
          * Respond to a remote capability request from the contact specified with the
          * capabilities of this device.
          * @param ownCapabilities The capabilities of this device.
-         * @hide
-         */
-        default void onRespondToCapabilityRequest(
-                @NonNull RcsContactUceCapability ownCapabilities) {}
-
-        /**
-         * Respond to a remote capability request from the contact specified with the
-         * capabilities of this device.
-         * @param ownCapabilities The capabilities of this device.
          * @param isBlocked Whether or not the user has blocked the number requesting the
          *         capabilities of this device. If true, the device should respond to the OPTIONS
          *         request with a 200 OK response and no capabilities.
          */
-        default void onRespondToCapabilityRequest(@NonNull RcsContactUceCapability ownCapabilities,
-                boolean isBlocked) {
-            Log.w("CapabilityExchangeEventListener", "implement "
-                    + "onRespondToCapabilityRequest(RcsContactUceCapability, boolean) instead!");
-            // Fall back to old implementation
-            if (isBlocked) {
-                onRespondToCapabilityRequestWithError(200, "OK");
-            } else {
-                onRespondToCapabilityRequest(ownCapabilities);
-            }
-        }
+        void onRespondToCapabilityRequest(@NonNull RcsContactUceCapability ownCapabilities,
+                boolean isBlocked);
 
         /**
          * Respond to a remote capability request from the contact specified with the
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
index cc050be..21aeb64 100644
--- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -37,6 +37,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
+import java.util.Arrays;
 import java.util.HashMap;
 
 /**
@@ -257,6 +258,16 @@
         public void setRcsClientConfiguration(RcsClientConfiguration rcc) throws RemoteException {
             getImsConfigImpl().setRcsClientConfiguration(rcc);
         }
+
+        @Override
+        public void notifyIntImsConfigChanged(int item, int value) throws RemoteException {
+            notifyImsConfigChanged(item, value);
+        }
+
+        @Override
+        public void notifyStringImsConfigChanged(int item, String value) throws RemoteException {
+            notifyImsConfigChanged(item, value);
+        }
     }
 
     /**
@@ -368,7 +379,13 @@
     }
 
     private void onNotifyRcsAutoConfigurationReceived(byte[] config, boolean isCompressed) {
-        mRcsConfigData = isCompressed ? RcsConfig.decompressGzip(config) : config;
+        // cache uncompressed config
+        config = isCompressed ? RcsConfig.decompressGzip(config) : config;
+        if (Arrays.equals(mRcsConfigData, config)) {
+            return;
+        }
+        mRcsConfigData = config;
+
         // can be null in testing
         if (mRcsCallbacks != null) {
             mRcsCallbacks.broadcastAction(c -> {
diff --git a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
index 5f8e93d..8ad40ed 100644
--- a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
@@ -57,10 +57,10 @@
                 } else if (listener != null && mListener == null) {
                     mListener = listener;
                 } else {
-                    // Fail fast here instead of silently overwriting the listener to another
-                    // listener due to another connection connecting.
-                    throw new IllegalStateException("ImsEcbmImplBase: Listener already set by "
-                            + "another connection.");
+                    // Warn that the listener is being replaced while active
+                    Log.w(TAG, "setListener is being called when there is already an active "
+                            + "listener");
+                    mListener = listener;
                 }
             }
         }
diff --git a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
index 8e961ac..ec1c7b3 100644
--- a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
@@ -62,10 +62,10 @@
                 } else if (listener != null && mListener == null) {
                     mListener = listener;
                 } else {
-                    // Fail fast here instead of silently overwriting the listener to another
-                    // listener due to another connection connecting.
-                    throw new IllegalStateException("ImsMultiEndpointImplBase: Listener already"
-                            + " set by another connection.");
+                    // Warn that the listener is being replaced while active
+                    Log.w(TAG, "setListener is being called when there is already an active "
+                            + "listener");
+                    mListener = listener;
                 }
             }
         }
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
index 83b89aa..eb3e8ed 100644
--- a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
@@ -224,11 +224,10 @@
                 } else if (listener != null && mUtListener == null) {
                     mUtListener = new ImsUtListener(listener);
                 } else {
-                    // This is a limitation of the current API surface, there can only be one
-                    // listener connected. Fail fast instead of silently overwriting the other
-                    // listener.
-                    throw new IllegalStateException("ImsUtImplBase#setListener: listener already "
-                            + "set by another connected interface!");
+                    // Warn that the listener is being replaced while active
+                    Log.w(TAG, "setListener is being called when there is already an active "
+                            + "listener");
+                    mUtListener = new ImsUtListener(listener);
                 }
             }
 
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 15d19a4..541292a 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -114,6 +114,7 @@
     public static final int EVENT_CARRIER_CONFIG_CHANGED = BASE + 54;
     public static final int EVENT_SIM_STATE_UPDATED = BASE + 55;
     public static final int EVENT_APN_UNTHROTTLED = BASE + 56;
+    public static final int EVENT_AIRPLANE_MODE_CHANGED = BASE + 57;
 
     /***** Constants *****/
 
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 5c25524..e87f3d9 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2055,6 +2055,11 @@
     int setImsProvisioningString(int subId, int key, String value);
 
     /**
+     * Start emergency callback mode for testing.
+     */
+    void startEmergencyCallbackMode();
+
+    /**
      * Update Emergency Number List for Test Mode.
      */
     void updateEmergencyNumberListTestMode(int action, in EmergencyNumber num);
@@ -2320,6 +2325,16 @@
     void triggerRcsReconfiguration(int subId);
 
     /**
+     * Enables or disables the test mode for RCS VoLTE single registration.
+     */
+    void setRcsSingleRegistrationTestModeEnabled(boolean enabled);
+
+    /**
+     * Gets the test mode for RCS VoLTE single registration.
+     */
+    boolean getRcsSingleRegistrationTestModeEnabled();
+
+    /**
      * Overrides the config of RCS VoLTE single registration enabled for the device.
      */
     void setDeviceSingleRegistrationEnabledOverride(String enabled);
diff --git a/tests/BatteryStatsPerfTest/Android.bp b/tests/BatteryStatsPerfTest/Android.bp
index 58ccec7..5233a5b 100644
--- a/tests/BatteryStatsPerfTest/Android.bp
+++ b/tests/BatteryStatsPerfTest/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+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_test {
     name: "BatteryStatsPerfTests",
     srcs: ["src/**/*.java"],
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index 7d29cdd..a8b7b05 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -21,8 +21,6 @@
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.NAV_BAR_LAYER_NAME
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.STATUS_BAR_WINDOW_NAME
 
-const val APP_PAIR_SPLIT_DIVIDER = "AppPairSplitDivider"
-const val DOCKED_STACK_DIVIDER = "DockedStackDivider"
 const val WALLPAPER_TITLE = "Wallpaper"
 
 fun FlickerTestParameter.statusBarWindowIsAlwaysVisible() {
@@ -64,9 +62,9 @@
 
 fun FlickerTestParameter.wallpaperWindowBecomesInvisible() {
     assertWm {
-        this.showsBelowAppWindow("Wallpaper")
+        this.showsBelowAppWindow(WALLPAPER_TITLE)
             .then()
-            .hidesBelowAppWindow("Wallpaper")
+            .hidesBelowAppWindow(WALLPAPER_TITLE)
     }
 }
 
@@ -103,19 +101,19 @@
     if (allStates) {
         assertLayers {
             if (startingBounds == endingBounds) {
-                this.coversAtLeastRegion(startingBounds)
+                this.coversAtLeast(startingBounds)
             } else {
-                this.coversAtLeastRegion(startingBounds)
+                this.coversAtLeast(startingBounds)
                     .then()
-                    .coversAtLeastRegion(endingBounds)
+                    .coversAtLeast(endingBounds)
             }
         }
     } else {
         assertLayersStart {
-            this.coversAtLeastRegion(startingBounds)
+            this.coversAtLeast(startingBounds)
         }
         assertLayersEnd {
-            this.coversAtLeastRegion(endingBounds)
+            this.coversAtLeast(endingBounds)
         }
     }
 }
@@ -124,15 +122,15 @@
 fun FlickerTestParameter.navBarLayerIsAlwaysVisible(rotatesScreen: Boolean = false) {
     if (rotatesScreen) {
         assertLayers {
-            this.showsLayer(NAV_BAR_LAYER_NAME)
+            this.isVisible(NAV_BAR_LAYER_NAME)
                 .then()
-                .hidesLayer(NAV_BAR_LAYER_NAME)
+                .isInvisible(NAV_BAR_LAYER_NAME)
                 .then()
-                .showsLayer(NAV_BAR_LAYER_NAME)
+                .isVisible(NAV_BAR_LAYER_NAME)
         }
     } else {
         assertLayers {
-            this.showsLayer(NAV_BAR_LAYER_NAME)
+            this.isVisible(NAV_BAR_LAYER_NAME)
         }
     }
 }
@@ -141,15 +139,15 @@
 fun FlickerTestParameter.statusBarLayerIsAlwaysVisible(rotatesScreen: Boolean = false) {
     if (rotatesScreen) {
         assertLayers {
-            this.showsLayer(STATUS_BAR_WINDOW_NAME)
+            this.isVisible(STATUS_BAR_WINDOW_NAME)
                 .then()
-            hidesLayer(STATUS_BAR_WINDOW_NAME)
+                .isInvisible(STATUS_BAR_WINDOW_NAME)
                 .then()
-                .showsLayer(STATUS_BAR_WINDOW_NAME)
+                .isVisible(STATUS_BAR_WINDOW_NAME)
         }
     } else {
         assertLayers {
-            this.showsLayer(STATUS_BAR_WINDOW_NAME)
+            this.isVisible(STATUS_BAR_WINDOW_NAME)
         }
     }
 }
@@ -163,10 +161,10 @@
     val endingPos = WindowUtils.getNavigationBarPosition(endRotation)
 
     assertLayersStart {
-        this.hasVisibleRegion(NAV_BAR_LAYER_NAME, startingPos)
+        this.coversExactly(startingPos, NAV_BAR_LAYER_NAME)
     }
     assertLayersEnd {
-        this.hasVisibleRegion(NAV_BAR_LAYER_NAME, endingPos)
+        this.coversExactly(endingPos, NAV_BAR_LAYER_NAME)
     }
 }
 
@@ -179,10 +177,10 @@
     val endingPos = WindowUtils.getStatusBarPosition(endRotation)
 
     assertLayersStart {
-        this.hasVisibleRegion(STATUS_BAR_WINDOW_NAME, startingPos)
+        this.coversExactly(startingPos, STATUS_BAR_WINDOW_NAME)
     }
     assertLayersEnd {
-        this.hasVisibleRegion(STATUS_BAR_WINDOW_NAME, endingPos)
+        this.coversExactly(endingPos, STATUS_BAR_WINDOW_NAME)
     }
 }
 
@@ -197,39 +195,41 @@
 
 fun FlickerTestParameter.appLayerReplacesWallpaperLayer(appName: String) {
     assertLayers {
-        this.showsLayer("Wallpaper")
+        this.isVisible(WALLPAPER_TITLE)
             .then()
-            .replaceVisibleLayer("Wallpaper", appName)
+            .isInvisible(WALLPAPER_TITLE)
+            .isVisible(appName)
     }
 }
 
 fun FlickerTestParameter.wallpaperLayerReplacesAppLayer(testApp: IAppHelper) {
     assertLayers {
-        this.showsLayer(testApp.getPackage())
+        this.isVisible(testApp.getPackage())
             .then()
-            .replaceVisibleLayer(testApp.getPackage(), WALLPAPER_TITLE)
+            .isInvisible(testApp.getPackage())
+            .isVisible(WALLPAPER_TITLE)
     }
 }
 
 fun FlickerTestParameter.layerAlwaysVisible(packageName: String) {
     assertLayers {
-        this.showsLayer(packageName)
+        this.isVisible(packageName)
     }
 }
 
 fun FlickerTestParameter.layerBecomesVisible(packageName: String) {
     assertLayers {
-        this.hidesLayer(packageName)
+        this.isInvisible(packageName)
             .then()
-            .showsLayer(packageName)
+            .isVisible(packageName)
     }
 }
 
 fun FlickerTestParameter.layerBecomesInvisible(packageName: String) {
     assertLayers {
-        this.showsLayer(packageName)
+        this.isVisible(packageName)
             .then()
-            .hidesLayer(packageName)
+            .isInvisible(packageName)
     }
 }
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index 38a88d3..26afb79 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -153,31 +153,11 @@
 
     @Presubmit
     @Test
-    fun navBarLayerIsAlwaysVisible() {
-        Assume.assumeFalse(testSpec.isRotated)
-        testSpec.navBarLayerIsAlwaysVisible()
-    }
-
-    @FlakyTest
-    @Test
-    fun navBarLayerIsAlwaysVisible_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
-        testSpec.navBarLayerIsAlwaysVisible()
-    }
+    fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
 
     @Presubmit
     @Test
-    fun statusBarLayerIsAlwaysVisible() {
-        Assume.assumeFalse(testSpec.isRotated)
-        testSpec.statusBarLayerIsAlwaysVisible()
-    }
-
-    @FlakyTest
-    @Test
-    fun statusBarLayerIsAlwaysVisible_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
-        testSpec.statusBarLayerIsAlwaysVisible()
-    }
+    fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
 
     @Presubmit
     @Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
index 476708c..2c4c627 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -17,9 +17,8 @@
 package com.android.server.wm.flicker.ime
 
 import android.app.Instrumentation
-import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
 import android.view.Surface
-import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.wm.flicker.FlickerBuilderProvider
@@ -85,55 +84,55 @@
         }
     }
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
         testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE))
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun imeAppWindowIsAlwaysVisible() = testSpec.imeAppWindowIsAlwaysVisible(testApp)
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun statusBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
 
-    @FlakyTest
+    @Presubmit
     @Test
     fun navBarLayerRotatesAndScales() =
         testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
 
-    @FlakyTest
+    @Presubmit
     @Test
     fun statusBarLayerRotatesScales() =
         testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun visibleLayersShownMoreThanOneConsecutiveEntry() =
         testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun imeAppLayerIsAlwaysVisible() = testSpec.imeAppLayerIsAlwaysVisible(testApp)
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index ac140f5..2bcdcd9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.ime
 
 import android.app.Instrumentation
-import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
@@ -91,63 +91,54 @@
         }
     }
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
         testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE))
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun imeWindowBecomesInvisible() = testSpec.imeWindowBecomesInvisible()
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun imeAppWindowBecomesInvisible() = testSpec.imeAppWindowBecomesInvisible(testApp)
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun statusBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
         Surface.ROTATION_0)
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun imeAppLayerBecomesInvisible() = testSpec.imeAppLayerBecomesInvisible(testApp)
 
-    @Postsubmit
+    @Presubmit
     @Test
-    fun navBarLayerRotatesAndScales() {
-        Assume.assumeFalse(testSpec.isRotated)
+    fun navBarLayerRotatesAndScales() =
         testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
 
-    @FlakyTest
-    @Test
-    fun navBarLayerRotatesAndScales_Flaky() {
-        Assume.assumeTrue(testSpec.isRotated)
-        testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
-    }
-
-    @Postsubmit
+    @Presubmit
     @Test
     fun statusBarLayerRotatesScales() {
         Assume.assumeFalse(testSpec.isRotated)
@@ -171,7 +162,8 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(repetitions = 5)
+                .getConfigNonRotationTests(repetitions = 5,
+                    supportedRotations = listOf(Surface.ROTATION_0))
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
index 212644c..3dfa31d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
@@ -23,23 +23,23 @@
 
 fun FlickerTestParameter.imeLayerBecomesVisible() {
     assertLayers {
-        this.hidesLayer(IME_WINDOW_TITLE)
+        this.isInvisible(IME_WINDOW_TITLE)
             .then()
-            .showsLayer(IME_WINDOW_TITLE)
+            .isVisible(IME_WINDOW_TITLE)
     }
 }
 
 fun FlickerTestParameter.imeLayerBecomesInvisible() {
     assertLayers {
-        this.showsLayer(IME_WINDOW_TITLE)
+        this.isVisible(IME_WINDOW_TITLE)
             .then()
-            .hidesLayer(IME_WINDOW_TITLE)
+            .isInvisible(IME_WINDOW_TITLE)
     }
 }
 
 fun FlickerTestParameter.imeAppLayerIsAlwaysVisible(testApp: IAppHelper) {
     assertLayers {
-        this.showsLayer(testApp.getPackage())
+        this.isVisible(testApp.getPackage())
     }
 }
 
@@ -83,9 +83,8 @@
 
 fun FlickerTestParameter.imeAppLayerBecomesInvisible(testApp: IAppHelper) {
     assertLayers {
-        this.skipUntilFirstAssertion()
-            .showsLayer(testApp.getPackage())
+        this.isVisible(testApp.getPackage())
             .then()
-            .hidesLayer(testApp.getPackage())
+            .isInvisible(testApp.getPackage())
     }
 }
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index c7a5178..6b2b930 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.ime
 
 import android.app.Instrumentation
-import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
@@ -89,43 +89,43 @@
         }
     }
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun imeWindowBecomesVisible() = testSpec.imeWindowBecomesVisible()
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun appWindowAlwaysVisibleOnTop() = testSpec.appWindowAlwaysVisibleOnTop(testApp.`package`)
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun imeLayerBecomesVisible() = testSpec.imeLayerBecomesVisible()
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun layerAlwaysVisible() = testSpec.layerAlwaysVisible(testApp.`package`)
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun navBarLayerRotatesAndScales() {
         Assume.assumeFalse(testSpec.isRotated)
@@ -139,7 +139,7 @@
         testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
     }
 
-    @Postsubmit
+    @Presubmit
     @Test
     fun statusBarLayerRotatesScales() {
         Assume.assumeFalse(testSpec.isRotated)
@@ -168,7 +168,8 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(repetitions = 5)
+                .getConfigNonRotationTests(repetitions = 5,
+                    supportedRotations = listOf(Surface.ROTATION_0))
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index e2a258a..18fac6a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -17,7 +17,6 @@
 package com.android.server.wm.flicker.launch
 
 import android.app.Instrumentation
-import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -148,17 +147,35 @@
     @Test
     fun focusChanges() = testSpec.focusChanges("NexusLauncherActivity", testApp.`package`)
 
-    @Postsubmit
+    @Presubmit
     @Test
-    fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+    fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+        Assume.assumeFalse(testSpec.isRotated)
         testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
+    }
 
     @FlakyTest
     @Test
-    fun visibleLayersShownMoreThanOneConsecutiveEntry() =
-        testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
+    fun visibleWindowsShownMoreThanOneConsecutiveEntry_Flaky() {
+        Assume.assumeTrue(testSpec.isRotated)
+        testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
+    }
 
-    @FlakyTest(bugId = 141361128)
+    @Presubmit
+    @Test
+    fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+        Assume.assumeFalse(testSpec.isRotated)
+        testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
+    }
+
+    @FlakyTest
+    @Test
+    fun visibleLayersShownMoreThanOneConsecutiveEntry_Flaky() {
+        Assume.assumeTrue(testSpec.isRotated)
+        testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
+    }
+
+    @Presubmit
     @Test
     fun noUncoveredRegions() = testSpec.noUncoveredRegions(Surface.ROTATION_0,
         testSpec.config.endRotation)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 386dafc5..b61310a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -102,7 +102,7 @@
     @Test
     fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
 
-    @Presubmit
+    @FlakyTest
     @Test
     fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
         testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 3cc509f..20e4b88 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -16,13 +16,13 @@
 
 package com.android.server.wm.flicker.rotation
 
-import android.os.Bundle
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.endRotation
 import com.android.server.wm.flicker.focusDoesNotChange
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
@@ -54,7 +54,15 @@
     testSpec: FlickerTestParameter
 ) : RotationTransition(testSpec) {
     override val testApp = SimpleAppHelper(instrumentation)
-    override fun getAppLaunchParams(configuration: Bundle): Map<String, String> = emptyMap()
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+        get() = {
+            super.transition(this, it)
+            setup {
+                test {
+                    testApp.launchViaIntent(wmHelper)
+                }
+            }
+        }
 
     @Presubmit
     @Test
@@ -78,11 +86,11 @@
     @Test
     fun screenshotLayerBecomesInvisible() {
         testSpec.assertLayers {
-            this.showsLayer(testApp.getPackage())
+            this.isVisible(testApp.getPackage())
                 .then()
-                .showsLayer(SCREENSHOT_LAYER)
+                .isVisible(SCREENSHOT_LAYER)
                 .then()
-                .showsLayer(testApp.getPackage())
+                .isVisible(testApp.getPackage())
         }
     }
 
@@ -113,7 +121,7 @@
     @Test
     fun appLayerRotates_StartingPos() {
         testSpec.assertLayersStart {
-            this.hasVisibleRegion(testApp.getPackage(), startingPos)
+            this.coversExactly(startingPos, testApp.getPackage())
         }
     }
 
@@ -121,7 +129,7 @@
     @Test
     fun appLayerRotates_EndingPos() {
         testSpec.assertLayersEnd {
-            this.hasVisibleRegion(testApp.getPackage(), endingPos)
+            this.coversExactly(endingPos, testApp.getPackage())
         }
     }
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
index 04ab84d..c391112 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
@@ -17,7 +17,6 @@
 package com.android.server.wm.flicker.rotation
 
 import android.app.Instrumentation
-import android.os.Bundle
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.wm.flicker.FlickerBuilderProvider
 import com.android.server.wm.flicker.FlickerTestParameter
@@ -31,36 +30,37 @@
 import com.android.server.wm.flicker.startRotation
 
 abstract class RotationTransition(protected val testSpec: FlickerTestParameter) {
+    protected abstract val testApp: StandardAppHelper
+
     protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
     protected val startingPos get() = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
     protected val endingPos get() = WindowUtils.getDisplayBounds(testSpec.config.endRotation)
 
-    protected abstract val testApp: StandardAppHelper
-    protected abstract fun getAppLaunchParams(configuration: Bundle): Map<String, String>
+    protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit = {
+        withTestName { testSpec.name }
+        repeat { testSpec.config.repetitions }
+        setup {
+            test {
+                device.wakeUpAndGoToHomeScreen()
+            }
+            eachRun {
+                this.setRotation(testSpec.config.startRotation)
+            }
+        }
+        teardown {
+            test {
+                testApp.exit()
+            }
+        }
+        transitions {
+            this.setRotation(testSpec.config.endRotation)
+        }
+    }
 
     @FlickerBuilderProvider
     fun buildFlicker(): FlickerBuilder {
         return FlickerBuilder(instrumentation).apply {
-            withTestName { testSpec.name }
-            repeat { testSpec.config.repetitions }
-            setup {
-                test {
-                    device.wakeUpAndGoToHomeScreen()
-                    val extras = getAppLaunchParams(testSpec.config)
-                    testApp.launchViaIntent(wmHelper, stringExtras = extras)
-                }
-                eachRun {
-                    this.setRotation(testSpec.config.startRotation)
-                }
-            }
-            teardown {
-                test {
-                    testApp.exit()
-                }
-            }
-            transitions {
-                this.setRotation(testSpec.config.endRotation)
-            }
+            transition(testSpec.config)
         }
     }
 }
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index ef1aead..fc5bcc7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -16,7 +16,6 @@
 
 package com.android.server.wm.flicker.rotation
 
-import android.os.Bundle
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
@@ -24,6 +23,7 @@
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.appWindowAlwaysVisibleOnTop
+import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.endRotation
 import com.android.server.wm.flicker.focusDoesNotChange
 import com.android.server.wm.flicker.helpers.SeamlessRotationAppHelper
@@ -58,9 +58,18 @@
 ) : RotationTransition(testSpec) {
     override val testApp = SeamlessRotationAppHelper(instrumentation)
 
-    override fun getAppLaunchParams(configuration: Bundle): Map<String, String> = mapOf(
-        ActivityOptions.EXTRA_STARVE_UI_THREAD to configuration.starveUiThread.toString()
-    )
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+        get() = {
+            super.transition(this, it)
+            setup {
+                test {
+                    testApp.launchViaIntent(wmHelper,
+                        stringExtras = mapOf(
+                            ActivityOptions.EXTRA_STARVE_UI_THREAD to it.starveUiThread.toString())
+                    )
+                }
+            }
+        }
 
     @Presubmit
     @Test
@@ -115,7 +124,7 @@
     @Test
     fun appLayerRotates() {
         testSpec.assertLayers {
-            this.hasVisibleRegion(testApp.`package`, startingPos)
+            this.coversExactly(startingPos, testApp.`package`)
         }
     }
 
@@ -126,12 +135,14 @@
     companion object {
         private val testFactory = FlickerTestParameterFactory.getInstance()
 
-        private val Bundle.starveUiThread
-            get() = this.getBoolean(ActivityOptions.EXTRA_STARVE_UI_THREAD, false)
+        private val Map<String, Any?>.starveUiThread
+            get() = this.getOrDefault(ActivityOptions.EXTRA_STARVE_UI_THREAD, false) as Boolean
 
-        private fun FlickerTestParameter.createConfig(starveUiThread: Boolean): Bundle {
-            val config = this.config.deepCopy()
-            config.putBoolean(ActivityOptions.EXTRA_STARVE_UI_THREAD, starveUiThread)
+        private fun FlickerTestParameter.createConfig(
+            starveUiThread: Boolean
+        ): MutableMap<String, Any?> {
+            val config = this.config.toMutableMap()
+            config[ActivityOptions.EXTRA_STARVE_UI_THREAD] = starveUiThread
             return config
         }
 
diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp
index a72b07c..335c8d0 100644
--- a/tests/Input/Android.bp
+++ b/tests/Input/Android.bp
@@ -1,3 +1,12 @@
+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_test {
     name: "InputTests",
     srcs: ["src/**/*.kt"],
diff --git a/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt b/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt
index f919a3e..c19e5cc 100644
--- a/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt
+++ b/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt
@@ -62,15 +62,12 @@
     fun testUpdateFrameInfoFromViewFrameInfo() {
         val frameInfo = FrameInfo()
         // By default, all values should be zero
-        assertThat(frameInfo.frameInfo[FrameInfo.OLDEST_INPUT_EVENT]).isEqualTo(0)
-        assertThat(frameInfo.frameInfo[FrameInfo.NEWEST_INPUT_EVENT]).isEqualTo(0)
+        // TODO(b/169866723): Use InputEventAssigner and assert INPUT_EVENT_ID
         assertThat(frameInfo.frameInfo[FrameInfo.FLAGS]).isEqualTo(0)
         assertThat(frameInfo.frameInfo[FrameInfo.DRAW_START]).isEqualTo(0)
 
         // The values inside FrameInfo should match those from ViewFrameInfo after we update them
         mViewFrameInfo.populateFrameInfo(frameInfo)
-        assertThat(frameInfo.frameInfo[FrameInfo.OLDEST_INPUT_EVENT]).isEqualTo(10)
-        assertThat(frameInfo.frameInfo[FrameInfo.NEWEST_INPUT_EVENT]).isEqualTo(20)
         assertThat(frameInfo.frameInfo[FrameInfo.FLAGS]).isEqualTo(
                 FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED)
         assertThat(frameInfo.frameInfo[FrameInfo.DRAW_START]).isGreaterThan(mTimeStarted)
diff --git a/tests/SilkFX/Android.bp b/tests/SilkFX/Android.bp
index 92e3efa..088d9a2 100644
--- a/tests/SilkFX/Android.bp
+++ b/tests/SilkFX/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+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_test {
     name: "SilkFX",
     srcs: ["**/*.java", "**/*.kt"],
diff --git a/tests/SurfaceViewBufferTests/Android.bp b/tests/SurfaceViewBufferTests/Android.bp
index 48031de..dc75f00 100644
--- a/tests/SurfaceViewBufferTests/Android.bp
+++ b/tests/SurfaceViewBufferTests/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+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_test {
     name: "SurfaceViewBufferTests",
     srcs: ["**/*.java","**/*.kt"],
diff --git a/tests/UpdatableSystemFontTest/Android.bp b/tests/UpdatableSystemFontTest/Android.bp
index 43a5078..d4f1ad3 100644
--- a/tests/UpdatableSystemFontTest/Android.bp
+++ b/tests/UpdatableSystemFontTest/Android.bp
@@ -12,18 +12,23 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 java_test_host {
     name: "UpdatableSystemFontTest",
     srcs: ["src/**/*.java"],
     libs: ["tradefed", "compatibility-tradefed", "compatibility-host-util"],
     static_libs: [
-        "block_device_writer_jar",
         "frameworks-base-hostutils",
     ],
     test_suites: ["general-tests", "vts"],
-    target_required: [
-        "block_device_writer_module",
-    ],
     data: [
         ":NotoColorEmojiTtf",
         ":UpdatableSystemFontTestCertDer",
diff --git a/tests/UpdatableSystemFontTest/AndroidTest.xml b/tests/UpdatableSystemFontTest/AndroidTest.xml
index 7b919bd..efe5d70 100644
--- a/tests/UpdatableSystemFontTest/AndroidTest.xml
+++ b/tests/UpdatableSystemFontTest/AndroidTest.xml
@@ -21,7 +21,6 @@
 
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
         <option name="cleanup" value="true" />
-        <option name="push" value="block_device_writer->/data/local/tmp/block_device_writer" />
         <option name="push" value="UpdatableSystemFontTestCert.der->/data/local/tmp/UpdatableSystemFontTestCert.der" />
         <option name="push" value="NotoColorEmoji.ttf->/data/local/tmp/NotoColorEmoji.ttf" />
         <option name="push" value="UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig" />
diff --git a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
index e249f8a9..92fa498 100644
--- a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
+++ b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java
@@ -21,7 +21,6 @@
 
 import android.platform.test.annotations.RootPermissionTest;
 
-import com.android.blockdevicewriter.BlockDeviceWriter;
 import com.android.fsverity.AddFsVerityCertRule;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.log.LogUtil.CLog;
@@ -144,30 +143,6 @@
         assertThat(fontPathAfterReboot).isEqualTo(fontPath);
     }
 
-    @Test
-    public void reboot_clearDamagedFiles() throws Exception {
-        expectRemoteCommandToSucceed(String.format("cmd font update %s %s",
-                TEST_NOTO_COLOR_EMOJI_V1_TTF, TEST_NOTO_COLOR_EMOJI_V1_TTF_FSV_SIG));
-        String fontPath = getFontPath(NOTO_COLOR_EMOJI_TTF);
-        assertThat(fontPath).startsWith("/data/fonts/files/");
-        assertThat(BlockDeviceWriter.canReadByte(getDevice(), fontPath, 0)).isTrue();
-
-        BlockDeviceWriter.damageFileAgainstBlockDevice(getDevice(), fontPath, 0);
-        expectRemoteCommandToSucceed("stop");
-        // We have to make sure system_server is gone before dropping caches, because system_server
-        // process holds font memory maps and prevents cache eviction.
-        waitUntilSystemServerIsGone();
-        BlockDeviceWriter.assertFileNotOpen(getDevice(), fontPath);
-        BlockDeviceWriter.dropCaches(getDevice());
-        assertThat(BlockDeviceWriter.canReadByte(getDevice(), fontPath, 0)).isFalse();
-
-        expectRemoteCommandToSucceed("start");
-        waitUntilFontCommandIsReady();
-        String fontPathAfterReboot = getFontPath(NOTO_COLOR_EMOJI_TTF);
-        assertWithMessage("Damaged file should be deleted")
-                .that(fontPathAfterReboot).startsWith("/system");
-    }
-
     private String getFontPath(String fontFileName) throws Exception {
         // TODO: add a dedicated command for testing.
         String lines = expectRemoteCommandToSucceed("cmd font dump");
diff --git a/tests/UpdatableSystemFontTest/testdata/Android.bp b/tests/UpdatableSystemFontTest/testdata/Android.bp
index 1296699..f744d5d 100644
--- a/tests/UpdatableSystemFontTest/testdata/Android.bp
+++ b/tests/UpdatableSystemFontTest/testdata/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 filegroup {
     name: "UpdatableSystemFontTestKeyPem",
     srcs: ["UpdatableSystemFontTestKey.pem"],
diff --git a/tests/benchmarks/internal/Android.bp b/tests/benchmarks/internal/Android.bp
index 9c34eaf..74ed7a3 100644
--- a/tests/benchmarks/internal/Android.bp
+++ b/tests/benchmarks/internal/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+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_test {
     name: "InternalBenchTests",
     srcs: ["src/**/*.java"],
@@ -23,4 +32,3 @@
     platform_apis: true,
     certificate: "platform"
 }
-
diff --git a/tests/net/common/java/android/net/CaptivePortalDataTest.kt b/tests/net/common/java/android/net/CaptivePortalDataTest.kt
index ad5bbf2..18a9331 100644
--- a/tests/net/common/java/android/net/CaptivePortalDataTest.kt
+++ b/tests/net/common/java/android/net/CaptivePortalDataTest.kt
@@ -55,14 +55,14 @@
             .build()
 
     private val dataFromPasspoint = CaptivePortalData.Builder()
-            .setUserPortalUrl(Uri.parse("https://tc.example.com/passpoint"),
-                    CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
-            .setVenueInfoUrl(Uri.parse("https://venue.example.com/passpoint"),
-                    CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
             .setCaptive(true)
             .apply {
                 if (SdkLevel.isAtLeastS()) {
                     setVenueFriendlyName("venue friendly name")
+                    setUserPortalUrl(Uri.parse("https://tc.example.com/passpoint"),
+                            CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
+                    setVenueInfoUrl(Uri.parse("https://venue.example.com/passpoint"),
+                            CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
                 }
             }
             .build()
@@ -96,28 +96,28 @@
         if (SdkLevel.isAtLeastS()) {
             assertNotEqualsAfterChange { it.setVenueFriendlyName("another friendly name") }
             assertNotEqualsAfterChange { it.setVenueFriendlyName(null) }
-        }
 
-        assertEquals(dataFromPasspoint, CaptivePortalData.Builder(dataFromPasspoint).build())
-        assertNotEqualsAfterChange { it.setUserPortalUrl(
-                Uri.parse("https://tc.example.com/passpoint")) }
-        assertNotEqualsAfterChange { it.setUserPortalUrl(
-                Uri.parse("https://tc.example.com/passpoint"),
-                CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
-        assertNotEqualsAfterChange { it.setUserPortalUrl(
-                Uri.parse("https://tc.example.com/other"),
-                CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) }
-        assertNotEqualsAfterChange { it.setUserPortalUrl(
-                Uri.parse("https://tc.example.com/passpoint"),
-                CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
-        assertNotEqualsAfterChange { it.setVenueInfoUrl(
-                Uri.parse("https://venue.example.com/passpoint")) }
-        assertNotEqualsAfterChange { it.setVenueInfoUrl(
-                Uri.parse("https://venue.example.com/other"),
-                CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) }
-        assertNotEqualsAfterChange { it.setVenueInfoUrl(
-                Uri.parse("https://venue.example.com/passpoint"),
-                CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
+            assertEquals(dataFromPasspoint, CaptivePortalData.Builder(dataFromPasspoint).build())
+            assertNotEqualsAfterChange { it.setUserPortalUrl(
+                    Uri.parse("https://tc.example.com/passpoint")) }
+            assertNotEqualsAfterChange { it.setUserPortalUrl(
+                    Uri.parse("https://tc.example.com/passpoint"),
+                    CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
+            assertNotEqualsAfterChange { it.setUserPortalUrl(
+                    Uri.parse("https://tc.example.com/other"),
+                    CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) }
+            assertNotEqualsAfterChange { it.setUserPortalUrl(
+                    Uri.parse("https://tc.example.com/passpoint"),
+                    CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
+            assertNotEqualsAfterChange { it.setVenueInfoUrl(
+                    Uri.parse("https://venue.example.com/passpoint")) }
+            assertNotEqualsAfterChange { it.setVenueInfoUrl(
+                    Uri.parse("https://venue.example.com/other"),
+                    CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) }
+            assertNotEqualsAfterChange { it.setVenueInfoUrl(
+                    Uri.parse("https://venue.example.com/passpoint"),
+                    CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
+        }
     }
 
     @Test
diff --git a/tests/net/common/java/android/net/NetworkStateSnapshotTest.kt b/tests/net/common/java/android/net/NetworkStateSnapshotTest.kt
new file mode 100644
index 0000000..0ca4d95
--- /dev/null
+++ b/tests/net/common/java/android/net/NetworkStateSnapshotTest.kt
@@ -0,0 +1,73 @@
+/*
+ * 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.net
+
+import android.net.ConnectivityManager.TYPE_NONE
+import android.net.ConnectivityManager.TYPE_WIFI
+import android.net.InetAddresses.parseNumericAddress
+import android.net.NetworkCapabilities.TRANSPORT_WIFI
+import android.os.Build
+import androidx.test.filters.SmallTest
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRunner
+import com.android.testutils.assertParcelSane
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.net.Inet4Address
+import java.net.Inet6Address
+
+private const val TEST_IMSI = "imsi1"
+private const val TEST_SSID = "SSID1"
+private const val TEST_NETID = 123
+
+private val TEST_IPV4_GATEWAY = parseNumericAddress("192.168.222.3") as Inet4Address
+private val TEST_IPV6_GATEWAY = parseNumericAddress("2001:db8::1") as Inet6Address
+private val TEST_IPV4_LINKADDR = LinkAddress("192.168.222.123/24")
+private val TEST_IPV6_LINKADDR = LinkAddress("2001:db8::123/64")
+private val TEST_IFACE = "fake0"
+private val TEST_LINK_PROPERTIES = LinkProperties().apply {
+    interfaceName = TEST_IFACE
+    addLinkAddress(TEST_IPV4_LINKADDR)
+    addLinkAddress(TEST_IPV6_LINKADDR)
+
+    // Add default routes
+    addRoute(RouteInfo(IpPrefix(parseNumericAddress("0.0.0.0"), 0), TEST_IPV4_GATEWAY))
+    addRoute(RouteInfo(IpPrefix(parseNumericAddress("::"), 0), TEST_IPV6_GATEWAY))
+}
+
+private val TEST_CAPABILITIES = NetworkCapabilities().apply {
+    addTransportType(TRANSPORT_WIFI)
+    setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false)
+    setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true)
+    setSSID(TEST_SSID)
+}
+
+@SmallTest
+@RunWith(DevSdkIgnoreRunner::class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
+class NetworkStateSnapshotTest {
+
+    @Test
+    fun testParcelUnparcel() {
+        val emptySnapshot = NetworkStateSnapshot(Network(TEST_NETID), NetworkCapabilities(),
+                LinkProperties(), null, TYPE_NONE)
+        val snapshot = NetworkStateSnapshot(
+                Network(TEST_NETID), TEST_CAPABILITIES, TEST_LINK_PROPERTIES, TEST_IMSI, TYPE_WIFI)
+        assertParcelSane(emptySnapshot, 5)
+        assertParcelSane(snapshot, 5)
+    }
+}
diff --git a/tests/net/common/java/android/net/UidRangeTest.java b/tests/net/common/java/android/net/UidRangeTest.java
new file mode 100644
index 0000000..1b1c954
--- /dev/null
+++ b/tests/net/common/java/android/net/UidRangeTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static android.os.UserHandle.MIN_SECONDARY_USER_ID;
+import static android.os.UserHandle.SYSTEM;
+import static android.os.UserHandle.USER_SYSTEM;
+import static android.os.UserHandle.getUid;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.os.Build;
+import android.os.UserHandle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class UidRangeTest {
+
+    /*
+     * UidRange is no longer passed to netd. UID ranges between the framework and netd are passed as
+     * UidRangeParcel objects.
+     */
+
+    @Rule
+    public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
+
+    @Test
+    public void testSingleItemUidRangeAllowed() {
+        new UidRange(123, 123);
+        new UidRange(0, 0);
+        new UidRange(Integer.MAX_VALUE, Integer.MAX_VALUE);
+    }
+
+    @Test
+    public void testNegativeUidsDisallowed() {
+        try {
+            new UidRange(-2, 100);
+            fail("Exception not thrown for negative start UID");
+        } catch (IllegalArgumentException expected) {
+        }
+
+        try {
+            new UidRange(-200, -100);
+            fail("Exception not thrown for negative stop UID");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    @Test
+    public void testStopLessThanStartDisallowed() {
+        final int x = 4195000;
+        try {
+            new UidRange(x, x - 1);
+            fail("Exception not thrown for negative-length UID range");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    @Test
+    public void testGetStartAndEndUser() throws Exception {
+        final UidRange uidRangeOfPrimaryUser = new UidRange(
+                getUid(USER_SYSTEM, 10000), getUid(USER_SYSTEM, 10100));
+        final UidRange uidRangeOfSecondaryUser = new UidRange(
+                getUid(MIN_SECONDARY_USER_ID, 10000), getUid(MIN_SECONDARY_USER_ID, 10100));
+        assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getStartUser());
+        assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getEndUser());
+        assertEquals(MIN_SECONDARY_USER_ID, uidRangeOfSecondaryUser.getStartUser());
+        assertEquals(MIN_SECONDARY_USER_ID, uidRangeOfSecondaryUser.getEndUser());
+
+        final UidRange uidRangeForDifferentUsers = new UidRange(
+                getUid(USER_SYSTEM, 10000), getUid(MIN_SECONDARY_USER_ID, 10100));
+        assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getStartUser());
+        assertEquals(MIN_SECONDARY_USER_ID, uidRangeOfSecondaryUser.getEndUser());
+    }
+
+    @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+    public void testCreateForUser() throws Exception {
+        final UidRange uidRangeOfPrimaryUser = UidRange.createForUser(SYSTEM);
+        final UidRange uidRangeOfSecondaryUser = UidRange.createForUser(
+                UserHandle.of(USER_SYSTEM + 1));
+        assertTrue(uidRangeOfPrimaryUser.stop < uidRangeOfSecondaryUser.start);
+        assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getStartUser());
+        assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getEndUser());
+        assertEquals(USER_SYSTEM + 1, uidRangeOfSecondaryUser.getStartUser());
+        assertEquals(USER_SYSTEM + 1, uidRangeOfSecondaryUser.getEndUser());
+    }
+}
diff --git a/tests/net/integration/Android.bp b/tests/net/integration/Android.bp
index 4d1e337..56f9df7 100644
--- a/tests/net/integration/Android.bp
+++ b/tests/net/integration/Android.bp
@@ -35,7 +35,7 @@
         "android.test.mock",
     ],
     static_libs: [
-        "TestNetworkStackLib",
+        "NetworkStackApiStableLib",
         "androidx.test.ext.junit",
         "frameworks-net-integration-testutils",
         "kotlin-reflect",
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
index 9ed55f0..c10c573 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
@@ -177,7 +177,7 @@
     }
 
     private inner class TestConnectivityService(deps: Dependencies) : ConnectivityService(
-            context, netManager, statsService, dnsResolver, log, netd, deps)
+            context, statsService, dnsResolver, log, netd, deps)
 
     private fun makeDependencies(): ConnectivityService.Dependencies {
         val deps = spy(ConnectivityService.Dependencies())
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
index dc9e587..e1da3d0 100644
--- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -17,6 +17,7 @@
 package com.android.server;
 
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
@@ -84,6 +85,7 @@
         final String typeName = ConnectivityManager.getNetworkTypeName(type);
         mNetworkCapabilities = (ncTemplate != null) ? ncTemplate : new NetworkCapabilities();
         mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
+        mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
         mNetworkCapabilities.addTransportType(transport);
         switch (transport) {
             case TRANSPORT_ETHERNET:
diff --git a/tests/net/java/android/net/IpSecAlgorithmTest.java b/tests/net/java/android/net/IpSecAlgorithmTest.java
index 2e1c29a..3a8d600 100644
--- a/tests/net/java/android/net/IpSecAlgorithmTest.java
+++ b/tests/net/java/android/net/IpSecAlgorithmTest.java
@@ -129,6 +129,7 @@
             checkCryptKeyLenValidation(IpSecAlgorithm.CRYPT_AES_CTR, len);
         }
         checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_AES_XCBC, 128, 96);
+        checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_AES_CMAC, 128, 96);
         checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305, 288, 128);
     }
 
diff --git a/tests/net/java/android/net/NetworkIdentityTest.kt b/tests/net/java/android/net/NetworkIdentityTest.kt
new file mode 100644
index 0000000..eb2b85c
--- /dev/null
+++ b/tests/net/java/android/net/NetworkIdentityTest.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.net
+
+import android.net.NetworkIdentity.OEM_NONE
+import android.net.NetworkIdentity.OEM_PAID
+import android.net.NetworkIdentity.OEM_PRIVATE
+import android.net.NetworkIdentity.getOemBitfield
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import kotlin.test.assertEquals
+
+@RunWith(JUnit4::class)
+class NetworkIdentityTest {
+    @Test
+    fun testGetOemBitfield() {
+        val oemNone = NetworkCapabilities().apply {
+            setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, false)
+            setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, false)
+        }
+        val oemPaid = NetworkCapabilities().apply {
+            setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, true)
+            setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, false)
+        }
+        val oemPrivate = NetworkCapabilities().apply {
+            setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, false)
+            setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, true)
+        }
+        val oemAll = NetworkCapabilities().apply {
+            setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, true)
+            setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, true)
+        }
+
+        assertEquals(getOemBitfield(oemNone), OEM_NONE)
+        assertEquals(getOemBitfield(oemPaid), OEM_PAID)
+        assertEquals(getOemBitfield(oemPrivate), OEM_PRIVATE)
+        assertEquals(getOemBitfield(oemAll), OEM_PAID or OEM_PRIVATE)
+    }
+}
diff --git a/tests/net/java/android/net/NetworkTemplateTest.kt b/tests/net/java/android/net/NetworkTemplateTest.kt
index b39555d..64b774c 100644
--- a/tests/net/java/android/net/NetworkTemplateTest.kt
+++ b/tests/net/java/android/net/NetworkTemplateTest.kt
@@ -20,14 +20,22 @@
 import android.net.ConnectivityManager.TYPE_MOBILE
 import android.net.ConnectivityManager.TYPE_WIFI
 import android.net.NetworkIdentity.SUBTYPE_COMBINED
+import android.net.NetworkIdentity.OEM_NONE
+import android.net.NetworkIdentity.OEM_PAID
+import android.net.NetworkIdentity.OEM_PRIVATE
 import android.net.NetworkIdentity.buildNetworkIdentity
 import android.net.NetworkStats.DEFAULT_NETWORK_ALL
 import android.net.NetworkStats.METERED_ALL
 import android.net.NetworkStats.ROAMING_ALL
 import android.net.NetworkTemplate.MATCH_MOBILE
+import android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD
 import android.net.NetworkTemplate.MATCH_WIFI
+import android.net.NetworkTemplate.MATCH_WIFI_WILDCARD
 import android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA
 import android.net.NetworkTemplate.NETWORK_TYPE_ALL
+import android.net.NetworkTemplate.OEM_MANAGED_ALL
+import android.net.NetworkTemplate.OEM_MANAGED_NO
+import android.net.NetworkTemplate.OEM_MANAGED_YES
 import android.net.NetworkTemplate.buildTemplateMobileWithRatType
 import android.telephony.TelephonyManager
 import com.android.testutils.assertParcelSane
@@ -37,6 +45,7 @@
 import org.junit.runners.JUnit4
 import org.mockito.Mockito.mock
 import org.mockito.MockitoAnnotations
+import kotlin.test.assertEquals
 import kotlin.test.assertFalse
 import kotlin.test.assertNotEquals
 import kotlin.test.assertTrue
@@ -49,23 +58,28 @@
 class NetworkTemplateTest {
     private val mockContext = mock(Context::class.java)
 
-    private fun buildMobileNetworkState(subscriberId: String): NetworkState =
+    private fun buildMobileNetworkState(subscriberId: String): NetworkStateSnapshot =
             buildNetworkState(TYPE_MOBILE, subscriberId = subscriberId)
-    private fun buildWifiNetworkState(ssid: String): NetworkState =
+    private fun buildWifiNetworkState(ssid: String): NetworkStateSnapshot =
             buildNetworkState(TYPE_WIFI, ssid = ssid)
 
     private fun buildNetworkState(
         type: Int,
         subscriberId: String? = null,
-        ssid: String? = null
-    ): NetworkState {
+        ssid: String? = null,
+        oemManaged: Int = OEM_NONE
+    ): NetworkStateSnapshot {
         val lp = LinkProperties()
         val caps = NetworkCapabilities().apply {
             setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false)
             setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true)
             setSSID(ssid)
+            setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID,
+                    (oemManaged and OEM_PAID) == OEM_PAID)
+            setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE,
+                    (oemManaged and OEM_PRIVATE) == OEM_PRIVATE)
         }
-        return NetworkState(type, lp, caps, mock(Network::class.java), subscriberId)
+        return NetworkStateSnapshot(mock(Network::class.java), caps, lp, subscriberId, type)
     }
 
     private fun NetworkTemplate.assertMatches(ident: NetworkIdentity) =
@@ -136,11 +150,15 @@
     @Test
     fun testParcelUnparcel() {
         val templateMobile = NetworkTemplate(MATCH_MOBILE, TEST_IMSI1, null, null, METERED_ALL,
-                ROAMING_ALL, DEFAULT_NETWORK_ALL, TelephonyManager.NETWORK_TYPE_LTE)
+                ROAMING_ALL, DEFAULT_NETWORK_ALL, TelephonyManager.NETWORK_TYPE_LTE,
+                OEM_MANAGED_ALL)
         val templateWifi = NetworkTemplate(MATCH_WIFI, null, null, TEST_SSID1, METERED_ALL,
-                ROAMING_ALL, DEFAULT_NETWORK_ALL, 0)
-        assertParcelSane(templateMobile, 8)
-        assertParcelSane(templateWifi, 8)
+                ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_ALL)
+        val templateOem = NetworkTemplate(MATCH_MOBILE, null, null, null, METERED_ALL,
+                ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_YES)
+        assertParcelSane(templateMobile, 9)
+        assertParcelSane(templateWifi, 9)
+        assertParcelSane(templateOem, 9)
     }
 
     // Verify NETWORK_TYPE_* constants in NetworkTemplate do not conflict with
@@ -152,4 +170,86 @@
             assertNotEquals(NETWORK_TYPE_5G_NSA, ratType)
         }
     }
+
+    @Test
+    fun testOemNetworkConstants() {
+        val constantValues = arrayOf(OEM_MANAGED_YES, OEM_MANAGED_ALL, OEM_MANAGED_NO,
+                OEM_PAID, OEM_PRIVATE, OEM_PAID or OEM_PRIVATE)
+
+        // Verify that "not OEM managed network" constants are equal.
+        assertEquals(OEM_MANAGED_NO, OEM_NONE)
+
+        // Verify the constants don't conflict.
+        assertEquals(constantValues.size, constantValues.distinct().count())
+    }
+
+    /**
+     * Helper to enumerate and assert OEM managed wifi and mobile {@code NetworkTemplate}s match
+     * their the appropriate OEM managed {@code NetworkIdentity}s.
+     *
+     * @param networkType {@code TYPE_MOBILE} or {@code TYPE_WIFI}
+     * @param matchType A match rule from {@code NetworkTemplate.MATCH_*} corresponding to the
+     *         networkType.
+     * @param subscriberId To be populated with {@code TEST_IMSI*} only if networkType is
+     *         {@code TYPE_MOBILE}. May be left as null when matchType is
+     *         {@link NetworkTemplate.MATCH_MOBILE_WILDCARD}.
+     * @param templateSsid Top be populated with {@code TEST_SSID*} only if networkType is
+     *         {@code TYPE_WIFI}. May be left as null when matchType is
+     *         {@link NetworkTemplate.MATCH_WIFI_WILDCARD}.
+     * @param identSsid If networkType is {@code TYPE_WIFI}, this value must *NOT* be null. Provide
+     *         one of {@code TEST_SSID*}.
+     */
+    private fun matchOemManagedIdent(
+        networkType: Int,
+        matchType: Int,
+        subscriberId: String? = null,
+        templateSsid: String? = null,
+        identSsid: String? = null
+    ) {
+        val oemManagedStates = arrayOf(OEM_NONE, OEM_PAID, OEM_PRIVATE, OEM_PAID or OEM_PRIVATE)
+        // A null subscriberId needs a null matchSubscriberIds argument as well.
+        val matchSubscriberIds = if (subscriberId == null) null else arrayOf(subscriberId)
+
+        val templateOemYes = NetworkTemplate(matchType, subscriberId, matchSubscriberIds,
+                templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
+                OEM_MANAGED_YES)
+        val templateOemAll = NetworkTemplate(matchType, subscriberId, matchSubscriberIds,
+                templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
+                OEM_MANAGED_ALL)
+
+        for (identityOemManagedState in oemManagedStates) {
+            val ident = buildNetworkIdentity(mockContext, buildNetworkState(networkType,
+                    subscriberId, identSsid, identityOemManagedState), /*defaultNetwork=*/false,
+                    /*subType=*/0)
+
+            // Create a template with each OEM managed type and match it against the NetworkIdentity
+            for (templateOemManagedState in oemManagedStates) {
+                val template = NetworkTemplate(matchType, subscriberId, matchSubscriberIds,
+                        templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL,
+                        NETWORK_TYPE_ALL, templateOemManagedState)
+                if (identityOemManagedState == templateOemManagedState) {
+                    template.assertMatches(ident)
+                } else {
+                    template.assertDoesNotMatch(ident)
+                }
+            }
+            // OEM_MANAGED_ALL ignores OEM state.
+            templateOemAll.assertMatches(ident)
+            if (identityOemManagedState == OEM_NONE) {
+                // OEM_MANAGED_YES matches everything except OEM_NONE.
+                templateOemYes.assertDoesNotMatch(ident)
+            } else {
+                templateOemYes.assertMatches(ident)
+            }
+        }
+    }
+
+    @Test
+    fun testOemManagedMatchesIdent() {
+        matchOemManagedIdent(TYPE_MOBILE, MATCH_MOBILE, subscriberId = TEST_IMSI1)
+        matchOemManagedIdent(TYPE_MOBILE, MATCH_MOBILE_WILDCARD)
+        matchOemManagedIdent(TYPE_WIFI, MATCH_WIFI, templateSsid = TEST_SSID1,
+                identSsid = TEST_SSID1)
+        matchOemManagedIdent(TYPE_WIFI, MATCH_WIFI_WILDCARD, identSsid = TEST_SSID1)
+    }
 }
diff --git a/tests/net/java/android/net/UidRangeTest.java b/tests/net/java/android/net/UidRangeTest.java
deleted file mode 100644
index ea1df09..0000000
--- a/tests/net/java/android/net/UidRangeTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static org.junit.Assert.fail;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class UidRangeTest {
-
-  /*
-   * UidRange is no longer passed to netd. UID ranges between the framework and netd are passed as
-   * UidRangeParcel objects.
-   */
-
-    @Test
-    public void testSingleItemUidRangeAllowed() {
-        new UidRange(123, 123);
-        new UidRange(0, 0);
-        new UidRange(Integer.MAX_VALUE, Integer.MAX_VALUE);
-    }
-
-    @Test
-    public void testNegativeUidsDisallowed() {
-        try {
-            new UidRange(-2, 100);
-            fail("Exception not thrown for negative start UID");
-        } catch (IllegalArgumentException expected) {
-        }
-
-        try {
-            new UidRange(-200, -100);
-            fail("Exception not thrown for negative stop UID");
-        } catch (IllegalArgumentException expected) {
-        }
-    }
-
-    @Test
-    public void testStopLessThanStartDisallowed() {
-        final int x = 4195000;
-        try {
-            new UidRange(x, x - 1);
-            fail("Exception not thrown for negative-length UID range");
-        } catch (IllegalArgumentException expected) {
-        }
-    }
-}
\ No newline at end of file
diff --git a/tests/net/java/android/net/VpnTransportInfoTest.java b/tests/net/java/android/net/VpnTransportInfoTest.java
index 866f38c..d04c87b 100644
--- a/tests/net/java/android/net/VpnTransportInfoTest.java
+++ b/tests/net/java/android/net/VpnTransportInfoTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 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.
diff --git a/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt b/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt
new file mode 100644
index 0000000..9b0cfa9
--- /dev/null
+++ b/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt
@@ -0,0 +1,137 @@
+/*
+ * 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.net.util
+
+import android.content.Context
+import android.content.res.Resources
+import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER
+import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE
+import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY
+import android.net.util.MultinetworkPolicyTracker.ActiveDataSubscriptionIdChangedListener
+import android.provider.Settings
+import android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI
+import android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE
+import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager
+import android.telephony.TelephonyManager
+import android.test.mock.MockContentResolver
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.internal.R
+import com.android.internal.util.test.FakeSettingsProvider
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.argThat
+import org.mockito.Mockito.any
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+
+/**
+ * Tests for [MultinetworkPolicyTracker].
+ *
+ * Build, install and run with:
+ * atest android.net.util.MultinetworkPolicyTrackerTest
+ */
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class MultinetworkPolicyTrackerTest {
+    private val resources = mock(Resources::class.java).also {
+        doReturn(0).`when`(it).getInteger(R.integer.config_networkAvoidBadWifi)
+    }
+    private val telephonyManager = mock(TelephonyManager::class.java)
+    private val subscriptionManager = mock(SubscriptionManager::class.java).also {
+        doReturn(null).`when`(it).getActiveSubscriptionInfo(anyInt())
+    }
+    private val resolver = MockContentResolver().apply {
+        addProvider(Settings.AUTHORITY, FakeSettingsProvider()) }
+    private val context = mock(Context::class.java).also {
+        doReturn(Context.TELEPHONY_SERVICE).`when`(it)
+                .getSystemServiceName(TelephonyManager::class.java)
+        doReturn(telephonyManager).`when`(it).getSystemService(Context.TELEPHONY_SERVICE)
+        doReturn(subscriptionManager).`when`(it)
+                .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)
+        doReturn(resolver).`when`(it).contentResolver
+        doReturn(resources).`when`(it).resources
+        doReturn(it).`when`(it).createConfigurationContext(any())
+        Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "1")
+    }
+    private val tracker = MultinetworkPolicyTracker(context, null /* handler */)
+
+    private fun assertMultipathPreference(preference: Int) {
+        Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
+                preference.toString())
+        tracker.updateMeteredMultipathPreference()
+        assertEquals(preference, tracker.meteredMultipathPreference)
+    }
+
+    @Test
+    fun testUpdateMeteredMultipathPreference() {
+        assertMultipathPreference(MULTIPATH_PREFERENCE_HANDOVER)
+        assertMultipathPreference(MULTIPATH_PREFERENCE_RELIABILITY)
+        assertMultipathPreference(MULTIPATH_PREFERENCE_PERFORMANCE)
+    }
+
+    @Test
+    fun testUpdateAvoidBadWifi() {
+        Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "0")
+        assertTrue(tracker.updateAvoidBadWifi())
+        assertFalse(tracker.avoidBadWifi)
+
+        doReturn(1).`when`(resources).getInteger(R.integer.config_networkAvoidBadWifi)
+        assertTrue(tracker.updateAvoidBadWifi())
+        assertTrue(tracker.avoidBadWifi)
+    }
+
+    @Test
+    fun testOnActiveDataSubscriptionIdChanged() {
+        val testSubId = 1000
+        val subscriptionInfo = SubscriptionInfo(testSubId, ""/* iccId */, 1/* iccId */,
+                "TMO"/* displayName */, "TMO"/* carrierName */, 1/* nameSource */, 1/* iconTint */,
+                "123"/* number */, 1/* roaming */, null/* icon */, "310"/* mcc */, "210"/* mnc */,
+                ""/* countryIso */, false/* isEmbedded */, null/* nativeAccessRules */,
+                "1"/* cardString */)
+        doReturn(subscriptionInfo).`when`(subscriptionManager).getActiveSubscriptionInfo(testSubId)
+
+        // Modify avoidBadWifi and meteredMultipathPreference settings value and local variables in
+        // MultinetworkPolicyTracker should be also updated after subId changed.
+        Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "0")
+        Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
+                MULTIPATH_PREFERENCE_PERFORMANCE.toString())
+
+        val listenerCaptor = ArgumentCaptor.forClass(
+                ActiveDataSubscriptionIdChangedListener::class.java)
+        verify(telephonyManager, times(1))
+                .registerPhoneStateListener(any(), listenerCaptor.capture())
+        val listener = listenerCaptor.value
+        listener.onActiveDataSubscriptionIdChanged(testSubId)
+
+        // Check it get resource value with test sub id.
+        verify(subscriptionManager, times(1)).getActiveSubscriptionInfo(testSubId)
+        verify(context).createConfigurationContext(argThat { it.mcc == 310 && it.mnc == 210 })
+
+        // Check if avoidBadWifi and meteredMultipathPreference values have been updated.
+        assertFalse(tracker.avoidBadWifi)
+        assertEquals(MULTIPATH_PREFERENCE_PERFORMANCE, tracker.meteredMultipathPreference)
+    }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 6de1075..c6e2bc7 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -91,6 +91,10 @@
 import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
 import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED;
 import static android.net.RouteInfo.RTN_UNREACHABLE;
+import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_ADDED;
+import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_REMOVED;
+import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE;
+import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS;
 import static android.os.Process.INVALID_UID;
 import static android.system.OsConstants.IPPROTO_TCP;
 
@@ -199,7 +203,7 @@
 import android.net.NetworkSpecifier;
 import android.net.NetworkStack;
 import android.net.NetworkStackClient;
-import android.net.NetworkState;
+import android.net.NetworkStateSnapshot;
 import android.net.NetworkTestResultParcelable;
 import android.net.OemNetworkPreferences;
 import android.net.ProxyInfo;
@@ -218,6 +222,8 @@
 import android.net.VpnManager;
 import android.net.VpnTransportInfo;
 import android.net.metrics.IpConnectivityLog;
+import android.net.resolv.aidl.Nat64PrefixEventParcel;
+import android.net.resolv.aidl.PrivateDnsValidationEventParcel;
 import android.net.shared.NetworkMonitorUtils;
 import android.net.shared.PrivateDnsConfig;
 import android.net.util.MultinetworkPolicyTracker;
@@ -244,7 +250,6 @@
 import android.os.UserManager;
 import android.provider.Settings;
 import android.security.Credentials;
-import android.security.KeyStore;
 import android.system.Os;
 import android.telephony.TelephonyManager;
 import android.telephony.data.EpsBearerQosSessionAttributes;
@@ -276,6 +281,7 @@
 import com.android.server.connectivity.ProxyTracker;
 import com.android.server.connectivity.QosCallbackTracker;
 import com.android.server.connectivity.Vpn;
+import com.android.server.connectivity.VpnProfileStore;
 import com.android.server.net.NetworkPinner;
 import com.android.server.net.NetworkPolicyManagerInternal;
 import com.android.testutils.ExceptionUtils;
@@ -345,6 +351,9 @@
     private static final String TAG = "ConnectivityServiceTest";
 
     private static final int TIMEOUT_MS = 500;
+    // Broadcasts can take a long time to be delivered. The test will not wait for that long unless
+    // there is a failure, so use a long timeout.
+    private static final int BROADCAST_TIMEOUT_MS = 30_000;
     private static final int TEST_LINGER_DELAY_MS = 400;
     private static final int TEST_NASCENT_DELAY_MS = 300;
     // Chosen to be less than the linger and nascent timeout. This ensures that we can distinguish
@@ -431,7 +440,7 @@
     @Mock MockableSystemProperties mSystemProperties;
     @Mock EthernetManager mEthernetManager;
     @Mock NetworkPolicyManager mNetworkPolicyManager;
-    @Mock KeyStore mKeyStore;
+    @Mock VpnProfileStore mVpnProfileStore;
     @Mock SystemConfigManager mSystemConfigManager;
 
     private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
@@ -1115,7 +1124,7 @@
                             return mDeviceIdleInternal;
                         }
                     },
-                    mNetworkManagementService, mMockNetd, userId, mKeyStore);
+                    mNetworkManagementService, mMockNetd, userId, mVpnProfileStore);
         }
 
         public void setUids(Set<UidRange> uids) {
@@ -1294,8 +1303,9 @@
                 return mVMSHandlerThread;
             }
 
-            public KeyStore getKeyStore() {
-                return mKeyStore;
+            @Override
+            public VpnProfileStore getVpnProfileStore() {
+                return mVpnProfileStore;
             }
 
             public INetd getNetd() {
@@ -1462,7 +1472,6 @@
         mDeps = makeDependencies();
         returnRealCallingUid();
         mService = new ConnectivityService(mServiceContext,
-                mNetworkManagementService,
                 mStatsService,
                 mMockDnsResolver,
                 mock(IpConnectivityLog.class),
@@ -1680,7 +1689,7 @@
         }
 
         public Intent expectBroadcast() throws Exception {
-            return expectBroadcast(TIMEOUT_MS);
+            return expectBroadcast(BROADCAST_TIMEOUT_MS);
         }
 
         public void expectNoBroadcast(int timeoutMs) throws Exception {
@@ -2797,6 +2806,10 @@
 
         NetworkCapabilities filter = new NetworkCapabilities();
         filter.addCapability(capability);
+        // Add NOT_VCN_MANAGED capability into filter unconditionally since some request will add
+        // NOT_VCN_MANAGED automatically but not for NetworkCapabilities,
+        // see {@code NetworkCapabilities#deduceNotVcnManagedCapability} for more details.
+        filter.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
         final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
         handlerThread.start();
         final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
@@ -4144,6 +4157,7 @@
         handlerThread.start();
         NetworkCapabilities filter = new NetworkCapabilities()
                 .addTransportType(TRANSPORT_CELLULAR)
+                .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
                 .addCapability(NET_CAPABILITY_INTERNET);
         final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
                 mServiceContext, "testFactory", filter, mCsHandlerThread);
@@ -5480,7 +5494,7 @@
                 UnderlyingNetworkInfo[].class);
 
         verify(mStatsService, atLeastOnce()).forceUpdateIfaces(networksCaptor.capture(),
-                any(NetworkState[].class), eq(defaultIface), vpnInfosCaptor.capture());
+                any(NetworkStateSnapshot[].class), eq(defaultIface), vpnInfosCaptor.capture());
 
         assertSameElementsNoDuplicates(networksCaptor.getValue(), networks);
 
@@ -5550,9 +5564,8 @@
         // Temp metered change shouldn't update ifaces
         mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED);
         waitForIdle();
-        verify(mStatsService, never())
-                .forceUpdateIfaces(eq(onlyCell), any(NetworkState[].class), eq(MOBILE_IFNAME),
-                        eq(new UnderlyingNetworkInfo[0]));
+        verify(mStatsService, never()).forceUpdateIfaces(eq(onlyCell), any(
+                NetworkStateSnapshot[].class), eq(MOBILE_IFNAME), eq(new UnderlyingNetworkInfo[0]));
         reset(mStatsService);
 
         // Roaming change should update ifaces
@@ -5634,7 +5647,7 @@
         // Confirm that we never tell NetworkStatsService that cell is no longer the underlying
         // network for the VPN...
         verify(mStatsService, never()).forceUpdateIfaces(any(Network[].class),
-                any(NetworkState[].class), any() /* anyString() doesn't match null */,
+                any(NetworkStateSnapshot[].class), any() /* anyString() doesn't match null */,
                 argThat(infos -> infos[0].underlyingIfaces.size() == 1
                         && WIFI_IFNAME.equals(infos[0].underlyingIfaces.get(0))));
         verifyNoMoreInteractions(mStatsService);
@@ -5648,7 +5661,7 @@
         mEthernetNetworkAgent.connect(false);
         waitForIdle();
         verify(mStatsService).forceUpdateIfaces(any(Network[].class),
-                any(NetworkState[].class), any() /* anyString() doesn't match null */,
+                any(NetworkStateSnapshot[].class), any() /* anyString() doesn't match null */,
                 argThat(vpnInfos -> vpnInfos[0].underlyingIfaces.size() == 1
                         && WIFI_IFNAME.equals(vpnInfos[0].underlyingIfaces.get(0))));
         mEthernetNetworkAgent.disconnect();
@@ -5916,6 +5929,16 @@
         assertEquals("strict.example.com", cbi.getLp().getPrivateDnsServerName());
     }
 
+    private PrivateDnsValidationEventParcel makePrivateDnsValidationEvent(
+            final int netId, final String ipAddress, final String hostname, final int validation) {
+        final PrivateDnsValidationEventParcel event = new PrivateDnsValidationEventParcel();
+        event.netId = netId;
+        event.ipAddress = ipAddress;
+        event.hostname = hostname;
+        event.validation = validation;
+        return event;
+    }
+
     @Test
     public void testLinkPropertiesWithPrivateDnsValidationEvents() throws Exception {
         // The default on Android is opportunistic mode ("Automatic").
@@ -5946,8 +5969,9 @@
 
         // Send a validation event for a server that is not part of the current
         // resolver config. The validation event should be ignored.
-        mService.mNetdEventCallback.onPrivateDnsValidationEvent(
-                mCellNetworkAgent.getNetwork().netId, "", "145.100.185.18", true);
+        mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent(
+                makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId, "",
+                        "145.100.185.18", VALIDATION_RESULT_SUCCESS));
         cellNetworkCallback.assertNoCallback();
 
         // Add a dns server to the LinkProperties.
@@ -5964,20 +5988,23 @@
 
         // Send a validation event containing a hostname that is not part of
         // the current resolver config. The validation event should be ignored.
-        mService.mNetdEventCallback.onPrivateDnsValidationEvent(
-                mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "hostname", true);
+        mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent(
+                makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId,
+                        "145.100.185.16", "hostname", VALIDATION_RESULT_SUCCESS));
         cellNetworkCallback.assertNoCallback();
 
         // Send a validation event where validation failed.
-        mService.mNetdEventCallback.onPrivateDnsValidationEvent(
-                mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "", false);
+        mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent(
+                makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId,
+                        "145.100.185.16", "", VALIDATION_RESULT_FAILURE));
         cellNetworkCallback.assertNoCallback();
 
         // Send a validation event where validation succeeded for a server in
         // the current resolver config. A LinkProperties callback with updated
         // private dns fields should be sent.
-        mService.mNetdEventCallback.onPrivateDnsValidationEvent(
-                mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "", true);
+        mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent(
+                makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId,
+                        "145.100.185.16", "", VALIDATION_RESULT_SUCCESS));
         cbi = cellNetworkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
                 mCellNetworkAgent);
         cellNetworkCallback.assertNoCallback();
@@ -6048,6 +6075,7 @@
                 .addTransportType(TRANSPORT_CELLULAR)
                 .addCapability(NET_CAPABILITY_INTERNET)
                 .addCapability(NET_CAPABILITY_NOT_CONGESTED)
+                .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
                 .setLinkDownstreamBandwidthKbps(10);
         final NetworkCapabilities wifiNc = new NetworkCapabilities()
                 .addTransportType(TRANSPORT_WIFI)
@@ -6056,6 +6084,7 @@
                 .addCapability(NET_CAPABILITY_NOT_ROAMING)
                 .addCapability(NET_CAPABILITY_NOT_CONGESTED)
                 .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
+                .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
                 .setLinkUpstreamBandwidthKbps(20);
         mCellNetworkAgent.setNetworkCapabilities(cellNc, true /* sendToConnectivityService */);
         mWiFiNetworkAgent.setNetworkCapabilities(wifiNc, true /* sendToConnectivityService */);
@@ -7481,8 +7510,7 @@
     private void setupLegacyLockdownVpn() {
         final String profileName = "testVpnProfile";
         final byte[] profileTag = profileName.getBytes(StandardCharsets.UTF_8);
-        when(mKeyStore.contains(Credentials.LOCKDOWN_VPN)).thenReturn(true);
-        when(mKeyStore.get(Credentials.LOCKDOWN_VPN)).thenReturn(profileTag);
+        when(mVpnProfileStore.get(Credentials.LOCKDOWN_VPN)).thenReturn(profileTag);
 
         final VpnProfile profile = new VpnProfile(profileName);
         profile.name = "My VPN";
@@ -7490,7 +7518,7 @@
         profile.dnsServers = "8.8.8.8";
         profile.type = VpnProfile.TYPE_IPSEC_XAUTH_PSK;
         final byte[] encodedProfile = profile.encode();
-        when(mKeyStore.get(Credentials.VPN + profileName)).thenReturn(encodedProfile);
+        when(mVpnProfileStore.get(Credentials.VPN + profileName)).thenReturn(encodedProfile);
     }
 
     private void establishLegacyLockdownVpn(Network underlying) throws Exception {
@@ -7748,19 +7776,13 @@
             mWiFiNetworkAgent.removeCapability(testCap);
             callbackWithCap.expectAvailableCallbacksValidated(mCellNetworkAgent);
             callbackWithoutCap.expectCapabilitiesWithout(testCap, mWiFiNetworkAgent);
-            // TODO: Test default network changes for NOT_VCN_MANAGED once the default request has
-            //  it.
-            if (testCap == NET_CAPABILITY_TRUSTED) {
-                verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
-                reset(mMockNetd);
-            }
+            verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
+            reset(mMockNetd);
 
             mCellNetworkAgent.removeCapability(testCap);
             callbackWithCap.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
             callbackWithoutCap.assertNoCallback();
-            if (testCap == NET_CAPABILITY_TRUSTED) {
-                verify(mMockNetd).networkClearDefault();
-            }
+            verify(mMockNetd).networkClearDefault();
 
             mCm.unregisterNetworkCallback(callbackWithCap);
             mCm.unregisterNetworkCallback(callbackWithoutCap);
@@ -7825,6 +7847,16 @@
         return stacked;
     }
 
+    private Nat64PrefixEventParcel makeNat64PrefixEvent(final int netId, final int prefixOperation,
+            final String prefixAddress, final int prefixLength) {
+        final Nat64PrefixEventParcel event = new Nat64PrefixEventParcel();
+        event.netId = netId;
+        event.prefixOperation = prefixOperation;
+        event.prefixAddress = prefixAddress;
+        event.prefixLength = prefixLength;
+        return event;
+    }
+
     @Test
     public void testStackedLinkProperties() throws Exception {
         final LinkAddress myIpv4 = new LinkAddress("1.2.3.4/24");
@@ -7855,7 +7887,6 @@
         cellLp.addRoute(defaultRoute);
         cellLp.addRoute(ipv6Subnet);
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
-        reset(mNetworkManagementService);
         reset(mMockDnsResolver);
         reset(mMockNetd);
         reset(mBatteryStatsService);
@@ -7895,7 +7926,6 @@
 
         verifyNoMoreInteractions(mMockNetd);
         verifyNoMoreInteractions(mMockDnsResolver);
-        reset(mNetworkManagementService);
         reset(mMockNetd);
         reset(mMockDnsResolver);
         when(mMockNetd.interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME))
@@ -7911,8 +7941,8 @@
         // When NAT64 prefix discovery succeeds, LinkProperties are updated and clatd is started.
         Nat464Xlat clat = getNat464Xlat(mCellNetworkAgent);
         assertNull(mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getNat64Prefix());
-        mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
-                kNat64PrefixString, 96);
+        mService.mResolverUnsolEventCallback.onNat64PrefixEvent(
+                makeNat64PrefixEvent(cellNetId, PREFIX_OPERATION_ADDED, kNat64PrefixString, 96));
         LinkProperties lpBeforeClat = networkCallback.expectCallback(
                 CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent).getLp();
         assertEquals(0, lpBeforeClat.getStackedLinks().size());
@@ -7952,8 +7982,8 @@
                 .thenReturn(getClatInterfaceConfigParcel(myIpv4));
         // Change the NAT64 prefix without first removing it.
         // Expect clatd to be stopped and started with the new prefix.
-        mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
-                kOtherNat64PrefixString, 96);
+        mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent(
+                cellNetId, PREFIX_OPERATION_ADDED, kOtherNat64PrefixString, 96));
         networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
                 (lp) -> lp.getStackedLinks().size() == 0);
         verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
@@ -7995,15 +8025,14 @@
         verify(mMockNetd, times(1)).networkRemoveInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME);
         verifyNoMoreInteractions(mMockNetd);
         verifyNoMoreInteractions(mMockDnsResolver);
-        reset(mNetworkManagementService);
         reset(mMockNetd);
         reset(mMockDnsResolver);
         when(mMockNetd.interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME))
                 .thenReturn(getClatInterfaceConfigParcel(myIpv4));
 
         // Stopping prefix discovery causes netd to tell us that the NAT64 prefix is gone.
-        mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
-                kOtherNat64PrefixString, 96);
+        mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent(
+                cellNetId, PREFIX_OPERATION_REMOVED, kOtherNat64PrefixString, 96));
         networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
                 (lp) -> lp.getNat64Prefix() == null);
 
@@ -8015,8 +8044,8 @@
         networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
         assertRoutesRemoved(cellNetId, ipv4Subnet);  // Directly-connected routes auto-added.
         verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
-        mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
-                kNat64PrefixString, 96);
+        mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent(
+                cellNetId, PREFIX_OPERATION_ADDED, kNat64PrefixString, 96));
         networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
         verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kNat64Prefix.toString());
 
@@ -8028,8 +8057,8 @@
         verify(mMockNetd, times(1)).networkAddInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME);
 
         // NAT64 prefix is removed. Expect that clat is stopped.
-        mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
-                kNat64PrefixString, 96);
+        mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent(
+                cellNetId, PREFIX_OPERATION_REMOVED, kNat64PrefixString, 96));
         networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
                 (lp) -> lp.getStackedLinks().size() == 0 && lp.getNat64Prefix() == null);
         assertRoutesRemoved(cellNetId, ipv4Subnet, stackedDefault);
@@ -8117,8 +8146,8 @@
         inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
         inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId);
 
-        mService.mNetdEventCallback.onNat64PrefixEvent(netId, true /* added */,
-                pref64FromDnsStr, 96);
+        mService.mResolverUnsolEventCallback.onNat64PrefixEvent(
+                makeNat64PrefixEvent(netId, PREFIX_OPERATION_ADDED, pref64FromDnsStr, 96));
         expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromDns);
         inOrder.verify(mMockNetd).clatdStart(iface, pref64FromDns.toString());
 
@@ -8151,8 +8180,8 @@
         inOrder.verify(mMockDnsResolver).stopPrefix64Discovery(netId);
 
         // Stopping prefix discovery results in a prefix removed notification.
-        mService.mNetdEventCallback.onNat64PrefixEvent(netId, false /* added */,
-                pref64FromDnsStr, 96);
+        mService.mResolverUnsolEventCallback.onNat64PrefixEvent(
+                makeNat64PrefixEvent(netId, PREFIX_OPERATION_REMOVED, pref64FromDnsStr, 96));
 
         inOrder.verify(mMockNetd).clatdStart(iface, pref64FromRa.toString());
         inOrder.verify(mMockDnsResolver).setPrefix64(netId, pref64FromRa.toString());
@@ -8190,8 +8219,8 @@
         inOrder.verify(mMockNetd).clatdStop(iface);
         inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
         inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId);
-        mService.mNetdEventCallback.onNat64PrefixEvent(netId, true /* added */,
-                pref64FromDnsStr, 96);
+        mService.mResolverUnsolEventCallback.onNat64PrefixEvent(
+                makeNat64PrefixEvent(netId, PREFIX_OPERATION_ADDED, pref64FromDnsStr, 96));
         expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromDns);
         inOrder.verify(mMockNetd).clatdStart(iface, pref64FromDns.toString());
         inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), any());
@@ -8232,7 +8261,6 @@
         final LinkProperties cellLp = new LinkProperties();
         cellLp.setInterfaceName(MOBILE_IFNAME);
         mCellNetworkAgent.sendLinkProperties(cellLp);
-        reset(mNetworkManagementService);
         mCellNetworkAgent.connect(true);
         networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         verify(mMockNetd, times(1)).idletimerAddInterface(eq(MOBILE_IFNAME), anyInt(),
@@ -8926,8 +8954,8 @@
                 ConnectivityManager.getNetworkTypeName(TYPE_MOBILE),
                 TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_LTE));
         return new NetworkAgentInfo(null, new Network(NET_ID), info, new LinkProperties(),
-                nc, 0, mServiceContext, null, new NetworkAgentConfig(), mService, null, null, null,
-                0, INVALID_UID, mQosCallbackTracker);
+                nc, 0, mServiceContext, null, new NetworkAgentConfig(), mService, null, null, 0,
+                INVALID_UID, mQosCallbackTracker);
     }
 
     @Test
diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
index f5b85ca..5760211 100644
--- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
@@ -22,6 +22,8 @@
 import static android.net.NetworkCapabilities.MIN_TRANSPORT;
 import static android.net.NetworkCapabilities.TRANSPORT_VPN;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE;
+import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS;
 import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE;
 import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
 import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
@@ -164,7 +166,8 @@
         mDnsManager.flushVmDnsCache();
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID_ALTERNATE,
-                InetAddress.parseNumericAddress("4.4.4.4"), "", true));
+                        InetAddress.parseNumericAddress("4.4.4.4"), "",
+                        VALIDATION_RESULT_SUCCESS));
         LinkProperties fixedLp = new LinkProperties(lp);
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
         assertFalse(fixedLp.isPrivateDnsActive());
@@ -204,7 +207,8 @@
         // Validate one.
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
-                InetAddress.parseNumericAddress("6.6.6.6"), "strictmode.com", true));
+                        InetAddress.parseNumericAddress("6.6.6.6"), "strictmode.com",
+                        VALIDATION_RESULT_SUCCESS));
         fixedLp = new LinkProperties(lp);
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
         assertEquals(Arrays.asList(InetAddress.parseNumericAddress("6.6.6.6")),
@@ -212,7 +216,8 @@
         // Validate the 2nd one.
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
-                InetAddress.parseNumericAddress("2001:db8:66:66::1"), "strictmode.com", true));
+                        InetAddress.parseNumericAddress("2001:db8:66:66::1"), "strictmode.com",
+                        VALIDATION_RESULT_SUCCESS));
         fixedLp = new LinkProperties(lp);
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
         assertEquals(Arrays.asList(
@@ -232,7 +237,8 @@
         mDnsManager.flushVmDnsCache();
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
-                InetAddress.parseNumericAddress("3.3.3.3"), "", true));
+                        InetAddress.parseNumericAddress("3.3.3.3"), "",
+                        VALIDATION_RESULT_SUCCESS));
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
         assertFalse(lp.isPrivateDnsActive());
         assertNull(lp.getPrivateDnsServerName());
@@ -245,7 +251,8 @@
         mDnsManager.flushVmDnsCache();
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID_UNTRACKED,
-                InetAddress.parseNumericAddress("3.3.3.3"), "", true));
+                        InetAddress.parseNumericAddress("3.3.3.3"), "",
+                        VALIDATION_RESULT_SUCCESS));
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
         assertFalse(lp.isPrivateDnsActive());
         assertNull(lp.getPrivateDnsServerName());
@@ -253,7 +260,8 @@
         // Validation event has untracked ipAddress
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
-                InetAddress.parseNumericAddress("4.4.4.4"), "", true));
+                        InetAddress.parseNumericAddress("4.4.4.4"), "",
+                        VALIDATION_RESULT_SUCCESS));
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
         assertFalse(lp.isPrivateDnsActive());
         assertNull(lp.getPrivateDnsServerName());
@@ -261,8 +269,8 @@
         // Validation event has untracked hostname
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
-                InetAddress.parseNumericAddress("3.3.3.3"), "hostname",
-                true));
+                        InetAddress.parseNumericAddress("3.3.3.3"), "hostname",
+                        VALIDATION_RESULT_SUCCESS));
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
         assertFalse(lp.isPrivateDnsActive());
         assertNull(lp.getPrivateDnsServerName());
@@ -270,7 +278,8 @@
         // Validation event failed
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
-                InetAddress.parseNumericAddress("3.3.3.3"), "", false));
+                        InetAddress.parseNumericAddress("3.3.3.3"), "",
+                        VALIDATION_RESULT_FAILURE));
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
         assertFalse(lp.isPrivateDnsActive());
         assertNull(lp.getPrivateDnsServerName());
@@ -279,7 +288,7 @@
         mDnsManager.removeNetwork(new Network(TEST_NETID));
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
-                InetAddress.parseNumericAddress("3.3.3.3"), "", true));
+                        InetAddress.parseNumericAddress("3.3.3.3"), "", VALIDATION_RESULT_SUCCESS));
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
         assertFalse(lp.isPrivateDnsActive());
         assertNull(lp.getPrivateDnsServerName());
@@ -293,7 +302,8 @@
         mDnsManager.flushVmDnsCache();
         mDnsManager.updatePrivateDnsValidation(
                 new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
-                InetAddress.parseNumericAddress("3.3.3.3"), "", true));
+                        InetAddress.parseNumericAddress("3.3.3.3"), "",
+                        VALIDATION_RESULT_SUCCESS));
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
         assertFalse(lp.isPrivateDnsActive());
         assertNull(lp.getPrivateDnsServerName());
@@ -398,7 +408,8 @@
         mDnsManager.updatePrivateDns(network, mDnsManager.getPrivateDnsConfig());
         mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
         mDnsManager.updatePrivateDnsValidation(
-                new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, dnsAddr, "", true));
+                new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, dnsAddr, "",
+                        VALIDATION_RESULT_SUCCESS));
         mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
         privateDnsCfg = mDnsManager.getPrivateDnsConfig(network);
         assertTrue(privateDnsCfg.useTls);
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 52cb836..a913673 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -41,7 +41,6 @@
 import android.net.NetworkInfo;
 import android.net.NetworkProvider;
 import android.os.Binder;
-import android.os.INetworkManagementService;
 import android.text.format.DateUtils;
 
 import androidx.test.filters.SmallTest;
@@ -74,7 +73,6 @@
     @Mock ConnectivityService mConnService;
     @Mock IDnsResolver mDnsResolver;
     @Mock INetd mNetd;
-    @Mock INetworkManagementService mNMS;
     @Mock Context mCtx;
     @Mock NetworkNotificationManager mNotifier;
     @Mock Resources mResources;
@@ -358,8 +356,8 @@
         caps.addTransportType(transport);
         NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info,
                 new LinkProperties(), caps, 50, mCtx, null, new NetworkAgentConfig() /* config */,
-                mConnService, mNetd, mDnsResolver, mNMS, NetworkProvider.ID_NONE,
-                Binder.getCallingUid(), mQosCallbackTracker);
+                mConnService, mNetd, mDnsResolver, NetworkProvider.ID_NONE, Binder.getCallingUid(),
+                mQosCallbackTracker);
         nai.everValidated = true;
         return nai;
     }
diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
index 4f65b67..5f56e25 100644
--- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
+++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
@@ -36,7 +36,6 @@
 import android.net.NetworkAgentConfig;
 import android.net.NetworkInfo;
 import android.os.Handler;
-import android.os.INetworkManagementService;
 import android.os.test.TestLooper;
 
 import androidx.test.filters.SmallTest;
@@ -67,7 +66,6 @@
     @Mock ConnectivityService mConnectivity;
     @Mock IDnsResolver mDnsResolver;
     @Mock INetd mNetd;
-    @Mock INetworkManagementService mNms;
     @Mock NetworkAgentInfo mNai;
 
     TestLooper mLooper;
@@ -75,7 +73,7 @@
     NetworkAgentConfig mAgentConfig = new NetworkAgentConfig();
 
     Nat464Xlat makeNat464Xlat() {
-        return new Nat464Xlat(mNai, mNetd, mDnsResolver, mNms) {
+        return new Nat464Xlat(mNai, mNetd, mDnsResolver) {
             @Override protected int getNetId() {
                 return NETID;
             }
@@ -206,7 +204,6 @@
         // Start clat.
         nat.start();
 
-        verify(mNms).registerObserver(eq(nat));
         verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
 
         // Stacked interface up notification arrives.
@@ -225,7 +222,6 @@
 
         verify(mNetd).clatdStop(eq(BASE_IFACE));
         verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
-        verify(mNms).unregisterObserver(eq(nat));
         assertTrue(c.getValue().getStackedLinks().isEmpty());
         assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
         verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
@@ -235,7 +231,7 @@
         nat.interfaceRemoved(STACKED_IFACE);
         mLooper.dispatchNext();
 
-        verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
+        verifyNoMoreInteractions(mNetd, mConnectivity);
     }
 
     @Test
@@ -346,7 +342,6 @@
 
         nat.start();
 
-        verify(mNms).registerObserver(eq(nat));
         verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
 
         // Stacked interface up notification arrives.
@@ -365,7 +360,6 @@
 
         verify(mNetd).clatdStop(eq(BASE_IFACE));
         verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
-        verify(mNms).unregisterObserver(eq(nat));
         verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
         assertTrue(c.getValue().getStackedLinks().isEmpty());
         assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
@@ -374,7 +368,7 @@
         // ConnectivityService stops clat: no-op.
         nat.stop();
 
-        verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
+        verifyNoMoreInteractions(mNetd, mConnectivity);
     }
 
     private void checkStopBeforeClatdStarts(boolean dueToDisconnect) throws Exception {
@@ -386,7 +380,6 @@
 
         nat.start();
 
-        verify(mNms).registerObserver(eq(nat));
         verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
 
         // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
@@ -394,7 +387,6 @@
         nat.stop();
 
         verify(mNetd).clatdStop(eq(BASE_IFACE));
-        verify(mNms).unregisterObserver(eq(nat));
         verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
         assertIdle(nat);
 
@@ -408,7 +400,7 @@
 
         assertIdle(nat);
 
-        verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
+        verifyNoMoreInteractions(mNetd, mConnectivity);
     }
 
     @Test
@@ -430,7 +422,6 @@
 
         nat.start();
 
-        verify(mNms).registerObserver(eq(nat));
         verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
 
         // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
@@ -438,11 +429,10 @@
         nat.stop();
 
         verify(mNetd).clatdStop(eq(BASE_IFACE));
-        verify(mNms).unregisterObserver(eq(nat));
         verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
         assertIdle(nat);
 
-        verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
+        verifyNoMoreInteractions(mNetd, mConnectivity);
     }
 
     @Test
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 7489a0f..b8f7fbc 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -91,7 +91,6 @@
 import android.os.test.TestLooper;
 import android.provider.Settings;
 import android.security.Credentials;
-import android.security.KeyStore;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Range;
@@ -196,7 +195,7 @@
     @Mock private Vpn.Ikev2SessionCreator mIkev2SessionCreator;
     @Mock private ConnectivityManager mConnectivityManager;
     @Mock private IpSecService mIpSecService;
-    @Mock private KeyStore mKeyStore;
+    @Mock private VpnProfileStore mVpnProfileStore;
     private final VpnProfile mVpnProfile;
 
     private IpSecManager mIpSecManager;
@@ -333,17 +332,17 @@
         assertFalse(vpn.getLockdown());
 
         // Set always-on without lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, Collections.emptyList(), mKeyStore));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, Collections.emptyList()));
         assertTrue(vpn.getAlwaysOn());
         assertFalse(vpn.getLockdown());
 
         // Set always-on with lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.emptyList(), mKeyStore));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.emptyList()));
         assertTrue(vpn.getAlwaysOn());
         assertTrue(vpn.getLockdown());
 
         // Remove always-on configuration.
-        assertTrue(vpn.setAlwaysOnPackage(null, false, Collections.emptyList(), mKeyStore));
+        assertTrue(vpn.setAlwaysOnPackage(null, false, Collections.emptyList()));
         assertFalse(vpn.getAlwaysOn());
         assertFalse(vpn.getLockdown());
     }
@@ -354,17 +353,17 @@
         final UidRange user = PRI_USER_RANGE;
 
         // Set always-on without lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null, mKeyStore));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null));
 
         // Set always-on with lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null, mKeyStore));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null));
         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
                 new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
                 new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop)
         }));
 
         // Switch to another app.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null, mKeyStore));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null));
         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
                 new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
                 new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop)
@@ -382,14 +381,14 @@
 
         // Set always-on with lockdown and allow app PKGS[2] from lockdown.
         assertTrue(vpn.setAlwaysOnPackage(
-                PKGS[1], true, Collections.singletonList(PKGS[2]), mKeyStore));
+                PKGS[1], true, Collections.singletonList(PKGS[2])));
         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
                 new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
                 new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop)
         }));
         // Change allowed app list to PKGS[3].
         assertTrue(vpn.setAlwaysOnPackage(
-                PKGS[1], true, Collections.singletonList(PKGS[3]), mKeyStore));
+                PKGS[1], true, Collections.singletonList(PKGS[3])));
         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
                 new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop)
         }));
@@ -400,7 +399,7 @@
 
         // Change the VPN app.
         assertTrue(vpn.setAlwaysOnPackage(
-                PKGS[0], true, Collections.singletonList(PKGS[3]), mKeyStore));
+                PKGS[0], true, Collections.singletonList(PKGS[3])));
         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
                 new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
                 new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1)
@@ -411,7 +410,7 @@
         }));
 
         // Remove the list of allowed packages.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null, mKeyStore));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null));
         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
                 new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1),
                 new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop)
@@ -422,7 +421,7 @@
 
         // Add the list of allowed packages.
         assertTrue(vpn.setAlwaysOnPackage(
-                PKGS[0], true, Collections.singletonList(PKGS[1]), mKeyStore));
+                PKGS[0], true, Collections.singletonList(PKGS[1])));
         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
                 new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.stop)
         }));
@@ -433,12 +432,12 @@
 
         // Try allowing a package with a comma, should be rejected.
         assertFalse(vpn.setAlwaysOnPackage(
-                PKGS[0], true, Collections.singletonList("a.b,c.d"), mKeyStore));
+                PKGS[0], true, Collections.singletonList("a.b,c.d")));
 
         // Pass a non-existent packages in the allowlist, they (and only they) should be ignored.
         // allowed package should change from PGKS[1] to PKGS[2].
         assertTrue(vpn.setAlwaysOnPackage(
-                PKGS[0], true, Arrays.asList("com.foo.app", PKGS[2], "com.bar.app"), mKeyStore));
+                PKGS[0], true, Arrays.asList("com.foo.app", PKGS[2], "com.bar.app")));
         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
                 new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
                 new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop)
@@ -525,22 +524,22 @@
                 .thenReturn(Collections.singletonList(resInfo));
 
         // null package name should return false
-        assertFalse(vpn.isAlwaysOnPackageSupported(null, mKeyStore));
+        assertFalse(vpn.isAlwaysOnPackageSupported(null));
 
         // Pre-N apps are not supported
         appInfo.targetSdkVersion = VERSION_CODES.M;
-        assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0], mKeyStore));
+        assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
 
         // N+ apps are supported by default
         appInfo.targetSdkVersion = VERSION_CODES.N;
-        assertTrue(vpn.isAlwaysOnPackageSupported(PKGS[0], mKeyStore));
+        assertTrue(vpn.isAlwaysOnPackageSupported(PKGS[0]));
 
         // Apps that opt out explicitly are not supported
         appInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
         Bundle metaData = new Bundle();
         metaData.putBoolean(VpnService.SERVICE_META_DATA_SUPPORTS_ALWAYS_ON, false);
         svcInfo.metaData = metaData;
-        assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0], mKeyStore));
+        assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
     }
 
     @Test
@@ -556,7 +555,7 @@
         order.verify(mNotificationManager, atLeastOnce()).cancel(anyString(), anyInt());
 
         // Start showing a notification for disconnected once always-on.
-        vpn.setAlwaysOnPackage(PKGS[0], false, null, mKeyStore);
+        vpn.setAlwaysOnPackage(PKGS[0], false, null);
         order.verify(mNotificationManager).notify(anyString(), anyInt(), any());
 
         // Stop showing the notification once connected.
@@ -568,7 +567,7 @@
         order.verify(mNotificationManager).notify(anyString(), anyInt(), any());
 
         // Notification should be cleared after unsetting always-on package.
-        vpn.setAlwaysOnPackage(null, false, null, mKeyStore);
+        vpn.setAlwaysOnPackage(null, false, null);
         order.verify(mNotificationManager).cancel(anyString(), anyInt());
     }
 
@@ -608,15 +607,13 @@
     }
 
     private void checkProvisionVpnProfile(Vpn vpn, boolean expectedResult, String... checkedOps) {
-        assertEquals(expectedResult, vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile, mKeyStore));
+        assertEquals(expectedResult, vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile));
 
         // The profile should always be stored, whether or not consent has been previously granted.
-        verify(mKeyStore)
+        verify(mVpnProfileStore)
                 .put(
                         eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)),
-                        eq(mVpnProfile.encode()),
-                        eq(Process.SYSTEM_UID),
-                        eq(0));
+                        eq(mVpnProfile.encode()));
 
         for (final String checkedOpStr : checkedOps) {
             verify(mAppOps).noteOpNoThrow(checkedOpStr, Process.myUid(), TEST_VPN_PKG,
@@ -671,7 +668,7 @@
         bigProfile.name = new String(new byte[Vpn.MAX_VPN_PROFILE_SIZE_BYTES + 1]);
 
         try {
-            vpn.provisionVpnProfile(TEST_VPN_PKG, bigProfile, mKeyStore);
+            vpn.provisionVpnProfile(TEST_VPN_PKG, bigProfile);
             fail("Expected IAE due to profile size");
         } catch (IllegalArgumentException expected) {
         }
@@ -684,7 +681,7 @@
                         restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
 
         try {
-            vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile, mKeyStore);
+            vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile);
             fail("Expected SecurityException due to restricted user");
         } catch (SecurityException expected) {
         }
@@ -694,10 +691,10 @@
     public void testDeleteVpnProfile() throws Exception {
         final Vpn vpn = createVpnAndSetupUidChecks();
 
-        vpn.deleteVpnProfile(TEST_VPN_PKG, mKeyStore);
+        vpn.deleteVpnProfile(TEST_VPN_PKG);
 
-        verify(mKeyStore)
-                .delete(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)), eq(Process.SYSTEM_UID));
+        verify(mVpnProfileStore)
+                .remove(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
     }
 
     @Test
@@ -707,7 +704,7 @@
                         restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
 
         try {
-            vpn.deleteVpnProfile(TEST_VPN_PKG, mKeyStore);
+            vpn.deleteVpnProfile(TEST_VPN_PKG);
             fail("Expected SecurityException due to restricted user");
         } catch (SecurityException expected) {
         }
@@ -717,24 +714,24 @@
     public void testGetVpnProfilePrivileged() throws Exception {
         final Vpn vpn = createVpnAndSetupUidChecks();
 
-        when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
+        when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
                 .thenReturn(new VpnProfile("").encode());
 
-        vpn.getVpnProfilePrivileged(TEST_VPN_PKG, mKeyStore);
+        vpn.getVpnProfilePrivileged(TEST_VPN_PKG);
 
-        verify(mKeyStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
+        verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
     }
 
     @Test
     public void testStartVpnProfile() throws Exception {
         final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
 
-        when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
+        when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
                 .thenReturn(mVpnProfile.encode());
 
-        vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore);
+        vpn.startVpnProfile(TEST_VPN_PKG);
 
-        verify(mKeyStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
+        verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
         verify(mAppOps)
                 .noteOpNoThrow(
                         eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
@@ -748,10 +745,10 @@
     public void testStartVpnProfileVpnServicePreconsented() throws Exception {
         final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_VPN);
 
-        when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
+        when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
                 .thenReturn(mVpnProfile.encode());
 
-        vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore);
+        vpn.startVpnProfile(TEST_VPN_PKG);
 
         // Verify that the the ACTIVATE_VPN appop was checked, but no error was thrown.
         verify(mAppOps).noteOpNoThrow(AppOpsManager.OPSTR_ACTIVATE_VPN, Process.myUid(),
@@ -763,7 +760,7 @@
         final Vpn vpn = createVpnAndSetupUidChecks();
 
         try {
-            vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore);
+            vpn.startVpnProfile(TEST_VPN_PKG);
             fail("Expected failure due to no user consent");
         } catch (SecurityException expected) {
         }
@@ -780,22 +777,22 @@
                 TEST_VPN_PKG, null /* attributionTag */, null /* message */);
 
         // Keystore should never have been accessed.
-        verify(mKeyStore, never()).get(any());
+        verify(mVpnProfileStore, never()).get(any());
     }
 
     @Test
     public void testStartVpnProfileMissingProfile() throws Exception {
         final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
 
-        when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))).thenReturn(null);
+        when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))).thenReturn(null);
 
         try {
-            vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore);
+            vpn.startVpnProfile(TEST_VPN_PKG);
             fail("Expected failure due to missing profile");
         } catch (IllegalArgumentException expected) {
         }
 
-        verify(mKeyStore).get(vpn.getProfileNameForPackage(TEST_VPN_PKG));
+        verify(mVpnProfileStore).get(vpn.getProfileNameForPackage(TEST_VPN_PKG));
         verify(mAppOps)
                 .noteOpNoThrow(
                         eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
@@ -812,7 +809,7 @@
                         restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
 
         try {
-            vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore);
+            vpn.startVpnProfile(TEST_VPN_PKG);
             fail("Expected SecurityException due to restricted user");
         } catch (SecurityException expected) {
         }
@@ -938,9 +935,9 @@
     }
 
     private void setAndVerifyAlwaysOnPackage(Vpn vpn, int uid, boolean lockdownEnabled) {
-        assertTrue(vpn.setAlwaysOnPackage(TEST_VPN_PKG, lockdownEnabled, null, mKeyStore));
+        assertTrue(vpn.setAlwaysOnPackage(TEST_VPN_PKG, lockdownEnabled, null));
 
-        verify(mKeyStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
+        verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
         verify(mAppOps).setMode(
                 eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN), eq(uid), eq(TEST_VPN_PKG),
                 eq(AppOpsManager.MODE_ALLOWED));
@@ -963,11 +960,11 @@
         final int uid = Process.myUid() + 1;
         when(mPackageManager.getPackageUidAsUser(eq(TEST_VPN_PKG), anyInt()))
                 .thenReturn(uid);
-        when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
+        when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
                 .thenReturn(mVpnProfile.encode());
 
         setAndVerifyAlwaysOnPackage(vpn, uid, false);
-        assertTrue(vpn.startAlwaysOnVpn(mKeyStore));
+        assertTrue(vpn.startAlwaysOnVpn());
 
         // TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in
         // a subsequent CL.
@@ -984,7 +981,7 @@
                         InetAddresses.parseNumericAddress("192.0.2.0"), EGRESS_IFACE);
         lp.addRoute(defaultRoute);
 
-        vpn.startLegacyVpn(vpnProfile, mKeyStore, EGRESS_NETWORK, lp);
+        vpn.startLegacyVpn(vpnProfile, EGRESS_NETWORK, lp);
         return vpn;
     }
 
@@ -1186,7 +1183,7 @@
                 .thenReturn(asUserContext);
         final TestLooper testLooper = new TestLooper();
         final Vpn vpn = new Vpn(testLooper.getLooper(), mContext, new TestDeps(), mNetService,
-                mNetd, userId, mKeyStore, mSystemServices, mIkev2SessionCreator);
+                mNetd, userId, mVpnProfileStore, mSystemServices, mIkev2SessionCreator);
         verify(mConnectivityManager, times(1)).registerNetworkProvider(argThat(
                 provider -> provider.getName().contains("VpnNetworkProvider")
         ));
diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
index 435c3c0..505ff9b 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
@@ -17,6 +17,7 @@
 package com.android.server.net;
 
 import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.NetworkIdentity.OEM_NONE;
 import static android.net.NetworkStats.SET_ALL;
 import static android.net.NetworkStats.SET_DEFAULT;
 import static android.net.NetworkStats.TAG_NONE;
@@ -213,7 +214,7 @@
         final NetworkStats.Entry entry = new NetworkStats.Entry();
         final NetworkIdentitySet identSet = new NetworkIdentitySet();
         identSet.add(new NetworkIdentity(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
-                TEST_IMSI, null, false, true, true));
+                TEST_IMSI, null, false, true, true, OEM_NONE));
 
         int myUid = Process.myUid();
         int otherUidInSameUser = Process.myUid() + 1;
@@ -468,7 +469,7 @@
         final NetworkStatsCollection large = new NetworkStatsCollection(HOUR_IN_MILLIS);
         final NetworkIdentitySet ident = new NetworkIdentitySet();
         ident.add(new NetworkIdentity(ConnectivityManager.TYPE_MOBILE, -1, TEST_IMSI, null,
-                false, true, true));
+                false, true, true, OEM_NONE));
         large.recordData(ident, UID_ALL, SET_ALL, TAG_NONE, TIME_A, TIME_B,
                 new NetworkStats.Entry(12_730_893_164L, 1, 0, 0, 0));
 
diff --git a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
index 291efc7..9fa1c50 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
@@ -17,6 +17,7 @@
 package com.android.server.net;
 
 import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.NetworkIdentity.OEM_NONE;
 import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
 import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
 import static android.net.NetworkStats.METERED_NO;
@@ -220,7 +221,7 @@
         identSet.add(new NetworkIdentity(
                 TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
                 IMSI_1, null /* networkId */, false /* roaming */, true /* metered */,
-                true /* defaultNetwork */));
+                true /* defaultNetwork */, OEM_NONE));
         return identSet;
     }
 
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index d644739..9334e2c 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -19,8 +19,9 @@
 import static android.content.Intent.ACTION_UID_REMOVED;
 import static android.content.Intent.EXTRA_UID;
 import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_VPN;
 import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.NetworkIdentity.OEM_PAID;
+import static android.net.NetworkIdentity.OEM_PRIVATE;
 import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
 import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
 import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
@@ -40,7 +41,10 @@
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
 import static android.net.NetworkStatsHistory.FIELD_ALL;
+import static android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD;
 import static android.net.NetworkTemplate.NETWORK_TYPE_ALL;
+import static android.net.NetworkTemplate.OEM_MANAGED_NO;
+import static android.net.NetworkTemplate.OEM_MANAGED_YES;
 import static android.net.NetworkTemplate.buildTemplateMobileAll;
 import static android.net.NetworkTemplate.buildTemplateMobileWithRatType;
 import static android.net.NetworkTemplate.buildTemplateWifi;
@@ -80,7 +84,7 @@
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
-import android.net.NetworkState;
+import android.net.NetworkStateSnapshot;
 import android.net.NetworkStats;
 import android.net.NetworkStatsHistory;
 import android.net.NetworkTemplate;
@@ -280,7 +284,7 @@
         // pretend that wifi network comes online; service should ask about full
         // network state, and poll any existing interfaces before updating.
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildWifiState()};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -323,7 +327,7 @@
         // pretend that wifi network comes online; service should ask about full
         // network state, and poll any existing interfaces before updating.
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildWifiState()};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -397,7 +401,7 @@
         // pretend that wifi network comes online; service should ask about full
         // network state, and poll any existing interfaces before updating.
         expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
-        NetworkState[] states = new NetworkState[] {buildWifiState()};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -438,7 +442,7 @@
     public void testUidStatsAcrossNetworks() throws Exception {
         // pretend first mobile network comes online
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildMobile3gState(IMSI_1)};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -469,7 +473,7 @@
         // disappearing, to verify we don't count backwards.
         incrementCurrentTime(HOUR_IN_MILLIS);
         expectDefaultSettings();
-        states = new NetworkState[] {buildMobile3gState(IMSI_2)};
+        states = new NetworkStateSnapshot[] {buildMobile3gState(IMSI_2)};
         expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
                 .insertEntry(TEST_IFACE, 2048L, 16L, 512L, 4L));
         expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
@@ -513,7 +517,7 @@
     public void testUidRemovedIsMoved() throws Exception {
         // pretend that network comes online
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildWifiState()};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -577,7 +581,8 @@
                 buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_LTE);
         final NetworkTemplate template5g =
                 buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_NR);
-        final NetworkState[] states = new NetworkState[]{buildMobile3gState(IMSI_1)};
+        final NetworkStateSnapshot[] states =
+                new NetworkStateSnapshot[]{buildMobile3gState(IMSI_1)};
 
         // 3G network comes online.
         expectNetworkStatsSummary(buildEmptyStats());
@@ -643,6 +648,117 @@
         assertUidTotal(template5g, UID_RED, 5L, 13L, 31L, 9L, 2);
     }
 
+    @Test
+    public void testMobileStatsOemManaged() throws Exception {
+        final NetworkTemplate templateOemPaid = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
+                /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
+                METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_PAID);
+
+        final NetworkTemplate templateOemPrivate = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
+                /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
+                METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_PRIVATE);
+
+        final NetworkTemplate templateOemAll = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
+                /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
+                METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
+                OEM_PAID | OEM_PRIVATE);
+
+        final NetworkTemplate templateOemYes = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
+                /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
+                METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_YES);
+
+        final NetworkTemplate templateOemNone = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
+                /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
+                METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_NO);
+
+        // OEM_PAID network comes online.
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{
+                buildOemManagedMobileState(IMSI_1, false,
+                new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PAID})};
+        expectNetworkStatsSummary(buildEmptyStats());
+        expectNetworkStatsUidDetail(buildEmptyStats());
+        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
+
+        // Create some traffic.
+        incrementCurrentTime(MINUTE_IN_MILLIS);
+        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+                .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
+                        36L, 41L, 24L, 96L, 0L)));
+        forcePollAndWaitForIdle();
+
+        // OEM_PRIVATE network comes online.
+        states = new NetworkStateSnapshot[]{buildOemManagedMobileState(IMSI_1, false,
+                new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE})};
+        expectNetworkStatsSummary(buildEmptyStats());
+        expectNetworkStatsUidDetail(buildEmptyStats());
+        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
+
+        // Create some traffic.
+        incrementCurrentTime(MINUTE_IN_MILLIS);
+        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+                .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
+                        49L, 71L, 72L, 48L, 0L)));
+        forcePollAndWaitForIdle();
+
+        // OEM_PAID + OEM_PRIVATE network comes online.
+        states = new NetworkStateSnapshot[]{buildOemManagedMobileState(IMSI_1, false,
+                new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE,
+                          NetworkCapabilities.NET_CAPABILITY_OEM_PAID})};
+        expectNetworkStatsSummary(buildEmptyStats());
+        expectNetworkStatsUidDetail(buildEmptyStats());
+        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
+
+        // Create some traffic.
+        incrementCurrentTime(MINUTE_IN_MILLIS);
+        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+                .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
+                        57L, 86L, 83L, 93L, 0L)));
+        forcePollAndWaitForIdle();
+
+        // OEM_NONE network comes online.
+        states = new NetworkStateSnapshot[]{buildOemManagedMobileState(IMSI_1, false, new int[]{})};
+        expectNetworkStatsSummary(buildEmptyStats());
+        expectNetworkStatsUidDetail(buildEmptyStats());
+        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+                new UnderlyingNetworkInfo[0]);
+
+        // Create some traffic.
+        incrementCurrentTime(MINUTE_IN_MILLIS);
+        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+                .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
+                        29L, 73L, 34L, 31L, 0L)));
+        forcePollAndWaitForIdle();
+
+        // Verify OEM_PAID template gets only relevant stats.
+        assertUidTotal(templateOemPaid, UID_RED, 36L, 41L, 24L, 96L, 0);
+
+        // Verify OEM_PRIVATE template gets only relevant stats.
+        assertUidTotal(templateOemPrivate, UID_RED, 49L, 71L, 72L, 48L, 0);
+
+        // Verify OEM_PAID + OEM_PRIVATE template gets only relevant stats.
+        assertUidTotal(templateOemAll, UID_RED, 57L, 86L, 83L, 93L, 0);
+
+        // Verify OEM_NONE sees only non-OEM managed stats.
+        assertUidTotal(templateOemNone, UID_RED, 29L, 73L, 34L, 31L, 0);
+
+        // Verify OEM_MANAGED_YES sees all OEM managed stats.
+        assertUidTotal(templateOemYes, UID_RED,
+                36L + 49L + 57L,
+                41L + 71L + 86L,
+                24L + 72L + 83L,
+                96L + 48L + 93L, 0);
+
+        // Verify ALL_MOBILE template gets both OEM managed and non-OEM managed stats.
+        assertUidTotal(sTemplateImsi1, UID_RED,
+                36L + 49L + 57L + 29L,
+                41L + 71L + 86L + 73L,
+                24L + 72L + 83L + 34L,
+                96L + 48L + 93L + 31L, 0);
+    }
+
     // TODO: support per IMSI state
     private void setMobileRatTypeAndWaitForIdle(int ratType) {
         when(mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(anyString()))
@@ -655,7 +771,7 @@
     public void testSummaryForAllUid() throws Exception {
         // pretend that network comes online
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildWifiState()};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -714,7 +830,7 @@
     public void testDetailedUidStats() throws Exception {
         // pretend that network comes online
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildWifiState()};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -755,9 +871,9 @@
         final String stackedIface = "stacked-test0";
         final LinkProperties stackedProp = new LinkProperties();
         stackedProp.setInterfaceName(stackedIface);
-        final NetworkState wifiState = buildWifiState();
+        final NetworkStateSnapshot wifiState = buildWifiState();
         wifiState.linkProperties.addStackedLink(stackedProp);
-        NetworkState[] states = new NetworkState[] {wifiState};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {wifiState};
 
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
@@ -813,7 +929,7 @@
     public void testForegroundBackground() throws Exception {
         // pretend that network comes online
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildWifiState()};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -870,8 +986,8 @@
     public void testMetered() throws Exception {
         // pretend that network comes online
         expectDefaultSettings();
-        NetworkState[] states =
-                new NetworkState[] {buildWifiState(true /* isMetered */, TEST_IFACE)};
+        NetworkStateSnapshot[] states =
+                new NetworkStateSnapshot[] {buildWifiState(true /* isMetered */, TEST_IFACE)};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -910,8 +1026,8 @@
     public void testRoaming() throws Exception {
         // pretend that network comes online
         expectDefaultSettings();
-        NetworkState[] states =
-            new NetworkState[] {buildMobile3gState(IMSI_1, true /* isRoaming */)};
+        NetworkStateSnapshot[] states =
+            new NetworkStateSnapshot[] {buildMobile3gState(IMSI_1, true /* isRoaming */)};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -949,7 +1065,8 @@
     public void testTethering() throws Exception {
         // pretend first mobile network comes online
         expectDefaultSettings();
-        final NetworkState[] states = new NetworkState[]{buildMobile3gState(IMSI_1)};
+        final NetworkStateSnapshot[] states =
+                new NetworkStateSnapshot[]{buildMobile3gState(IMSI_1)};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -1006,7 +1123,7 @@
         // pretend that wifi network comes online; service should ask about full
         // network state, and poll any existing interfaces before updating.
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[] {buildWifiState()};
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -1104,8 +1221,8 @@
     public void testStatsProviderUpdateStats() throws Exception {
         // Pretend that network comes online.
         expectDefaultSettings();
-        final NetworkState[] states =
-                new NetworkState[]{buildWifiState(true /* isMetered */, TEST_IFACE)};
+        final NetworkStateSnapshot[] states =
+                new NetworkStateSnapshot[]{buildWifiState(true /* isMetered */, TEST_IFACE)};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
 
@@ -1166,8 +1283,8 @@
     public void testStatsProviderSetAlert() throws Exception {
         // Pretend that network comes online.
         expectDefaultSettings();
-        NetworkState[] states =
-                new NetworkState[]{buildWifiState(true /* isMetered */, TEST_IFACE)};
+        NetworkStateSnapshot[] states =
+                new NetworkStateSnapshot[]{buildWifiState(true /* isMetered */, TEST_IFACE)};
         mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
                 new UnderlyingNetworkInfo[0]);
 
@@ -1210,7 +1327,8 @@
                 buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UNKNOWN);
         final NetworkTemplate templateAll =
                 buildTemplateMobileWithRatType(null, NETWORK_TYPE_ALL);
-        final NetworkState[] states = new NetworkState[]{buildMobile3gState(IMSI_1)};
+        final NetworkStateSnapshot[] states =
+                new NetworkStateSnapshot[]{buildMobile3gState(IMSI_1)};
 
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
@@ -1285,7 +1403,7 @@
     public void testOperationCount_nonDefault_traffic() throws Exception {
         // Pretend mobile network comes online, but wifi is the default network.
         expectDefaultSettings();
-        NetworkState[] states = new NetworkState[]{
+        NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{
                 buildWifiState(true /*isMetered*/, TEST_IFACE2), buildMobile3gState(IMSI_1)};
         expectNetworkStatsUidDetail(buildEmptyStats());
         mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states),
@@ -1373,7 +1491,7 @@
         expectNetworkStatsSummary(buildEmptyStats());
     }
 
-    private String getActiveIface(NetworkState... states) throws Exception {
+    private String getActiveIface(NetworkStateSnapshot... states) throws Exception {
         if (states == null || states.length == 0 || states[0].linkProperties == null) {
             return null;
         }
@@ -1449,11 +1567,11 @@
         assertEquals("unexpected operations", operations, entry.operations);
     }
 
-    private static NetworkState buildWifiState() {
+    private static NetworkStateSnapshot buildWifiState() {
         return buildWifiState(false, TEST_IFACE);
     }
 
-    private static NetworkState buildWifiState(boolean isMetered, @NonNull String iface) {
+    private static NetworkStateSnapshot buildWifiState(boolean isMetered, @NonNull String iface) {
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(iface);
         final NetworkCapabilities capabilities = new NetworkCapabilities();
@@ -1461,31 +1579,41 @@
         capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
         capabilities.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
         capabilities.setSSID(TEST_SSID);
-        return new NetworkState(TYPE_WIFI, prop, capabilities, WIFI_NETWORK, null);
+        return new NetworkStateSnapshot(WIFI_NETWORK, capabilities, prop, null, TYPE_WIFI);
     }
 
-    private static NetworkState buildMobile3gState(String subscriberId) {
+    private static NetworkStateSnapshot buildMobile3gState(String subscriberId) {
         return buildMobile3gState(subscriberId, false /* isRoaming */);
     }
 
-    private static NetworkState buildMobile3gState(String subscriberId, boolean isRoaming) {
+    private static NetworkStateSnapshot buildMobile3gState(String subscriberId, boolean isRoaming) {
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(TEST_IFACE);
         final NetworkCapabilities capabilities = new NetworkCapabilities();
         capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
         capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, !isRoaming);
         capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-        return new NetworkState(TYPE_MOBILE, prop, capabilities, MOBILE_NETWORK, subscriberId);
+        return new NetworkStateSnapshot(
+                MOBILE_NETWORK, capabilities, prop, subscriberId, TYPE_MOBILE);
     }
 
     private NetworkStats buildEmptyStats() {
         return new NetworkStats(getElapsedRealtime(), 0);
     }
 
-    private static NetworkState buildVpnState() {
+    private static NetworkStateSnapshot buildOemManagedMobileState(
+            String subscriberId, boolean isRoaming, int[] oemNetCapabilities) {
         final LinkProperties prop = new LinkProperties();
-        prop.setInterfaceName(TUN_IFACE);
-        return new NetworkState(TYPE_VPN, prop, new NetworkCapabilities(), VPN_NETWORK, null);
+        prop.setInterfaceName(TEST_IFACE);
+        final NetworkCapabilities capabilities = new NetworkCapabilities();
+        capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
+        capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, !isRoaming);
+        for (int nc : oemNetCapabilities) {
+            capabilities.setCapability(nc, true);
+        }
+        capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+        return new NetworkStateSnapshot(MOBILE_NETWORK, capabilities, prop, subscriberId,
+                TYPE_MOBILE);
     }
 
     private long getElapsedRealtime() {
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java
new file mode 100644
index 0000000..28cf38a
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.net.vcn.persistablebundleutils;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.InetAddresses;
+import android.net.ipsec.ike.IkeTrafficSelector;
+import android.os.PersistableBundle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.InetAddress;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IkeTrafficSelectorUtilsTest {
+    private static final int START_PORT = 16;
+    private static final int END_PORT = 65520;
+
+    private static final InetAddress IPV4_START_ADDRESS =
+            InetAddresses.parseNumericAddress("192.0.2.100");
+    private static final InetAddress IPV4_END_ADDRESS =
+            InetAddresses.parseNumericAddress("192.0.2.101");
+
+    private static final InetAddress IPV6_START_ADDRESS =
+            InetAddresses.parseNumericAddress("2001:db8:2::100");
+    private static final InetAddress IPV6_END_ADDRESS =
+            InetAddresses.parseNumericAddress("2001:db8:2::101");
+
+    private static void verifyPersistableBundleEncodeDecodeIsLossless(IkeTrafficSelector ts) {
+        final PersistableBundle bundle = IkeTrafficSelectorUtils.toPersistableBundle(ts);
+        final IkeTrafficSelector resultTs = IkeTrafficSelectorUtils.fromPersistableBundle(bundle);
+        assertEquals(ts, resultTs);
+    }
+
+    @Test
+    public void testPersistableBundleEncodeDecodeIsLosslessIpv4Ts() throws Exception {
+        verifyPersistableBundleEncodeDecodeIsLossless(
+                new IkeTrafficSelector(START_PORT, END_PORT, IPV4_START_ADDRESS, IPV4_END_ADDRESS));
+    }
+
+    @Test
+    public void testPersistableBundleEncodeDecodeIsLosslessIpv6Ts() throws Exception {
+        verifyPersistableBundleEncodeDecodeIsLossless(
+                new IkeTrafficSelector(START_PORT, END_PORT, IPV6_START_ADDRESS, IPV6_END_ADDRESS));
+    }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index 69c21b9..69b2fb1 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -36,6 +36,7 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 
@@ -143,11 +144,18 @@
                 .onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform());
         mTestLooper.dispatchAll();
 
+        verify(mIpSecSvc, times(2))
+                .setNetworkForTunnelInterface(
+                        eq(TEST_IPSEC_TUNNEL_RESOURCE_ID),
+                        eq(TEST_UNDERLYING_NETWORK_RECORD_1.network),
+                        any());
+
         for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) {
             verify(mIpSecSvc)
                     .applyTunnelModeTransform(
                             eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(direction), anyInt(), any());
         }
+
         assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
     }
 
@@ -290,4 +298,22 @@
         verifyIkeSessionClosedExceptionalltyNotifiesStatusCallback(
                 new TemporaryFailureException("vcn test"), VCN_ERROR_CODE_INTERNAL_ERROR);
     }
+
+    @Test
+    public void testTeardown() throws Exception {
+        mGatewayConnection.teardownAsynchronously();
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+        assertTrue(mGatewayConnection.isQuitting());
+    }
+
+    @Test
+    public void testNonTeardownDisconnectRequest() throws Exception {
+        mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+        assertFalse(mGatewayConnection.isQuitting());
+    }
 }
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
index 17ae19e..d07d2cf 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
@@ -19,6 +19,8 @@
 import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -111,4 +113,22 @@
     public void testSafeModeTimeoutNotifiesCallback() {
         verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mConnectingState);
     }
+
+    @Test
+    public void testTeardown() throws Exception {
+        mGatewayConnection.teardownAsynchronously();
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+        assertTrue(mGatewayConnection.isQuitting());
+    }
+
+    @Test
+    public void testNonTeardownDisconnectRequest() throws Exception {
+        mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+        assertFalse(mGatewayConnection.isQuitting());
+    }
 }
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
index 9ea641f..5f27fab 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
@@ -21,9 +21,12 @@
 import static com.android.server.vcn.VcnGatewayConnection.DUMMY_ADDR;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
 import android.net.IpSecManager;
@@ -54,7 +57,7 @@
     }
 
     @Test
-    public void testEnterWhileNotRunningTriggersQuit() throws Exception {
+    public void testEnterWhileQuittingTriggersQuit() throws Exception {
         final VcnGatewayConnection vgc =
                 new VcnGatewayConnection(
                         mVcnContext,
@@ -64,7 +67,7 @@
                         mGatewayStatusCallback,
                         mDeps);
 
-        vgc.setIsRunning(false);
+        vgc.setIsQuitting(true);
         vgc.transitionTo(vgc.mDisconnectedState);
         mTestLooper.dispatchAll();
 
@@ -101,5 +104,18 @@
         assertNull(mGatewayConnection.getCurrentState());
         verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any());
         verifySafeModeTimeoutAlarmAndGetCallback(true /* expectCanceled */);
+        assertTrue(mGatewayConnection.isQuitting());
+        verify(mGatewayStatusCallback).onQuit();
+    }
+
+    @Test
+    public void testNonTeardownDisconnectRequest() throws Exception {
+        mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
+        assertFalse(mGatewayConnection.isQuitting());
+        verify(mGatewayStatusCallback, never()).onQuit();
+        // No safe mode timer changes expected.
     }
 }
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
index 7385204..661e03a 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
@@ -18,6 +18,8 @@
 
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
@@ -79,10 +81,20 @@
         // Should do nothing; already tearing down.
         assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
         verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+        assertTrue(mGatewayConnection.isQuitting());
     }
 
     @Test
     public void testSafeModeTimeoutNotifiesCallback() {
         verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mDisconnectingState);
     }
+
+    @Test
+    public void testNonTeardownDisconnectRequest() throws Exception {
+        mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+        assertFalse(mGatewayConnection.isQuitting());
+    }
 }
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
index 5b0850b..85a0277 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
@@ -17,6 +17,9 @@
 package com.android.server.vcn;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -96,4 +99,22 @@
     public void testSafeModeTimeoutNotifiesCallback() {
         verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mRetryTimeoutState);
     }
+
+    @Test
+    public void testTeardownDisconnectRequest() throws Exception {
+        mGatewayConnection.teardownAsynchronously();
+        mTestLooper.dispatchAll();
+
+        assertNull(mGatewayConnection.getCurrentState());
+        assertTrue(mGatewayConnection.isQuitting());
+    }
+
+    @Test
+    public void testNonTeardownDisconnectRequest() throws Exception {
+        mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
+        assertFalse(mGatewayConnection.isQuitting());
+    }
 }
diff --git a/tests/vcn/java/com/android/server/vcn/VcnTest.java b/tests/vcn/java/com/android/server/vcn/VcnTest.java
index 9d33682..3dd710a 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnTest.java
@@ -16,6 +16,10 @@
 
 package com.android.server.vcn;
 
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.mockito.Matchers.any;
@@ -33,6 +37,7 @@
 import android.net.vcn.VcnGatewayConnectionConfigTest;
 import android.os.ParcelUuid;
 import android.os.test.TestLooper;
+import android.util.ArraySet;
 
 import com.android.server.VcnManagementService.VcnCallback;
 import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
@@ -51,6 +56,11 @@
     private static final ParcelUuid TEST_SUB_GROUP = new ParcelUuid(new UUID(0, 0));
     private static final int NETWORK_SCORE = 0;
     private static final int PROVIDER_ID = 5;
+    private static final int[][] TEST_CAPS =
+            new int[][] {
+                new int[] {NET_CAPABILITY_INTERNET, NET_CAPABILITY_MMS},
+                new int[] {NET_CAPABILITY_DUN}
+            };
 
     private Context mContext;
     private VcnContext mVcnContext;
@@ -91,13 +101,12 @@
         mGatewayStatusCallbackCaptor = ArgumentCaptor.forClass(VcnGatewayStatusCallback.class);
 
         final VcnConfig.Builder configBuilder = new VcnConfig.Builder(mContext);
-        for (final int capability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) {
+        for (final int[] caps : TEST_CAPS) {
             configBuilder.addGatewayConnectionConfig(
-                    VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(capability));
+                    VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(caps));
         }
-        configBuilder.addGatewayConnectionConfig(VcnGatewayConnectionConfigTest.buildTestConfig());
-        mConfig = configBuilder.build();
 
+        mConfig = configBuilder.build();
         mVcn =
                 new Vcn(
                         mVcnContext,
@@ -130,8 +139,7 @@
     @Test
     public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() {
         final NetworkRequestListener requestListener = verifyAndGetRequestListener();
-        startVcnGatewayWithCapabilities(
-                requestListener, VcnGatewayConnectionConfigTest.EXPOSED_CAPS);
+        startVcnGatewayWithCapabilities(requestListener, TEST_CAPS[0]);
 
         final Set<VcnGatewayConnection> gatewayConnections = mVcn.getVcnGatewayConnections();
         assertFalse(gatewayConnections.isEmpty());
@@ -153,10 +161,19 @@
         for (final int capability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) {
             startVcnGatewayWithCapabilities(requestListener, capability);
         }
+    }
 
-        // Each Capability in EXPOSED_CAPS was split into a separate VcnGatewayConnection in #setUp.
-        // Expect one VcnGatewayConnection per capability.
-        final int numExpectedGateways = VcnGatewayConnectionConfigTest.EXPOSED_CAPS.length;
+    private void triggerVcnRequestListeners(NetworkRequestListener requestListener) {
+        for (final int[] caps : TEST_CAPS) {
+            startVcnGatewayWithCapabilities(requestListener, caps);
+        }
+    }
+
+    public Set<VcnGatewayConnection> startGatewaysAndGetGatewayConnections(
+            NetworkRequestListener requestListener) {
+        triggerVcnRequestListeners(requestListener);
+
+        final int numExpectedGateways = TEST_CAPS.length;
 
         final Set<VcnGatewayConnection> gatewayConnections = mVcn.getVcnGatewayConnections();
         assertEquals(numExpectedGateways, gatewayConnections.size());
@@ -168,7 +185,16 @@
                         any(),
                         mGatewayStatusCallbackCaptor.capture());
 
-        // Doesn't matter which callback this gets - any Gateway entering safe mode should shut down
+        return gatewayConnections;
+    }
+
+    @Test
+    public void testGatewayEnteringSafemodeNotifiesVcn() {
+        final NetworkRequestListener requestListener = verifyAndGetRequestListener();
+        final Set<VcnGatewayConnection> gatewayConnections =
+                startGatewaysAndGetGatewayConnections(requestListener);
+
+        // Doesn't matter which callback this gets - any Gateway entering Safemode should shut down
         // all Gateways
         final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
         statusCallback.onEnteredSafeMode();
@@ -181,4 +207,31 @@
         verify(mVcnNetworkProvider).unregisterListener(requestListener);
         verify(mVcnCallback).onEnteredSafeMode();
     }
+
+    @Test
+    public void testGatewayQuit() {
+        final NetworkRequestListener requestListener = verifyAndGetRequestListener();
+        final Set<VcnGatewayConnection> gatewayConnections =
+                new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener));
+
+        final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
+        statusCallback.onQuit();
+        mTestLooper.dispatchAll();
+
+        // Verify that the VCN requests the networkRequests be resent
+        assertEquals(1, mVcn.getVcnGatewayConnections().size());
+        verify(mVcnNetworkProvider).resendAllRequests(requestListener);
+
+        // Verify that the VcnGatewayConnection is restarted
+        triggerVcnRequestListeners(requestListener);
+        mTestLooper.dispatchAll();
+        assertEquals(2, mVcn.getVcnGatewayConnections().size());
+        verify(mDeps, times(gatewayConnections.size() + 1))
+                .newVcnGatewayConnection(
+                        eq(mVcnContext),
+                        eq(TEST_SUB_GROUP),
+                        eq(mSubscriptionSnapshot),
+                        any(),
+                        mGatewayStatusCallbackCaptor.capture());
+    }
 }
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index b760958..13e090d 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -2263,6 +2263,16 @@
     return 1;
   }
 
+  if (shared_lib_ && options_.private_symbols) {
+    // If a shared library styleable in a public R.java uses a private attribute, attempting to
+    // reference the private attribute within the styleable array will cause a link error because
+    // the private attribute will not be emitted in the public R.java.
+    context.GetDiagnostics()->Error(DiagMessage()
+                                    << "--shared-lib cannot currently be used in combination with"
+                                    << " --private-symbols");
+    return 1;
+  }
+
   if (options_.merge_only && !static_lib_) {
     context.GetDiagnostics()->Error(
         DiagMessage() << "the --merge-only flag can be only used when building a static library");
diff --git a/tools/aapt2/cmd/Link_test.cpp b/tools/aapt2/cmd/Link_test.cpp
index 062dd8e..73072a9 100644
--- a/tools/aapt2/cmd/Link_test.cpp
+++ b/tools/aapt2/cmd/Link_test.cpp
@@ -14,13 +14,16 @@
  * limitations under the License.
  */
 
-#include "AppInfo.h"
 #include "Link.h"
 
+#include <android-base/file.h>
+
+#include "AppInfo.h"
 #include "LoadedApk.h"
 #include "test/Test.h"
 
 using testing::Eq;
+using testing::HasSubstr;
 using testing::Ne;
 
 namespace aapt {
@@ -317,4 +320,76 @@
   ASSERT_TRUE(Link(link_args, feature2_files_dir, &diag));
 }
 
+TEST_F(LinkTest, SharedLibraryAttributeRJava) {
+  StdErrDiagnostics diag;
+  const std::string lib_values =
+      R"(<resources>
+           <attr name="foo"/>
+           <public type="attr" name="foo" id="0x00010001"/>
+           <declare-styleable name="LibraryStyleable">
+             <attr name="foo" />
+           </declare-styleable>
+         </resources>)";
+
+  const std::string client_values =
+      R"(<resources>
+           <attr name="bar" />
+           <declare-styleable name="ClientStyleable">
+             <attr name="com.example.lib:foo" />
+             <attr name="bar" />
+           </declare-styleable>
+         </resources>)";
+
+  // Build a library with a public attribute
+  const std::string lib_res = GetTestPath("library-res");
+  ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"), lib_values, lib_res, &diag));
+
+  const std::string lib_apk = GetTestPath("library.apk");
+  const std::string lib_java = GetTestPath("library_java");
+  // clang-format off
+  auto lib_manifest = ManifestBuilder(this)
+      .SetPackageName("com.example.lib")
+      .Build();
+
+  auto lib_link_args = LinkCommandBuilder(this)
+      .SetManifestFile(lib_manifest)
+      .AddFlag("--shared-lib")
+      .AddParameter("--java", lib_java)
+      .AddCompiledResDir(lib_res, &diag)
+      .Build(lib_apk);
+  // clang-format on
+  ASSERT_TRUE(Link(lib_link_args, &diag));
+
+  const std::string lib_r_java = lib_java + "/com/example/lib/R.java";
+  std::string lib_r_contents;
+  ASSERT_TRUE(android::base::ReadFileToString(lib_r_java, &lib_r_contents));
+  EXPECT_THAT(lib_r_contents, HasSubstr(" public static int foo=0x00010001;"));
+  EXPECT_THAT(lib_r_contents, HasSubstr(" com.example.lib.R.attr.foo"));
+
+  // Build a client that uses the library attribute in a declare-styleable
+  const std::string client_res = GetTestPath("client-res");
+  ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"), client_values, client_res, &diag));
+
+  const std::string client_apk = GetTestPath("client.apk");
+  const std::string client_java = GetTestPath("client_java");
+  // clang-format off
+  auto client_manifest = ManifestBuilder(this)
+      .SetPackageName("com.example.client")
+      .Build();
+
+  auto client_link_args = LinkCommandBuilder(this)
+      .SetManifestFile(client_manifest)
+      .AddParameter("--java", client_java)
+      .AddParameter("-I", lib_apk)
+      .AddCompiledResDir(client_res, &diag)
+      .Build(client_apk);
+  // clang-format on
+  ASSERT_TRUE(Link(client_link_args, &diag));
+
+  const std::string client_r_java = client_java + "/com/example/client/R.java";
+  std::string client_r_contents;
+  ASSERT_TRUE(android::base::ReadFileToString(client_r_java, &client_r_contents));
+  EXPECT_THAT(client_r_contents, HasSubstr(" com.example.lib.R.attr.foo, 0x7f010000"));
+}
+
 }  // namespace aapt
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index eb0ade6..4b90b4f 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -570,7 +570,6 @@
       ResourceEntry* entry = sorted_entries->at(entryIndex);
 
       // Populate the config masks for this entry.
-
       if (entry->visibility.level == Visibility::Level::kPublic) {
         config_masks[entry->id.value()] |= util::HostToDevice32(ResTable_typeSpec::SPEC_PUBLIC);
       }
diff --git a/tools/aapt2/java/ClassDefinition.h b/tools/aapt2/java/ClassDefinition.h
index 1e4b681..995495a 100644
--- a/tools/aapt2/java/ClassDefinition.h
+++ b/tools/aapt2/java/ClassDefinition.h
@@ -70,8 +70,8 @@
     return name_;
   }
 
-  void Print(bool final, text::Printer* printer, bool strip_api_annotations = false)
-      const override {
+  void Print(bool final, text::Printer* printer,
+             bool strip_api_annotations = false) const override {
     using std::to_string;
 
     ClassMember::Print(final, printer, strip_api_annotations);
@@ -127,13 +127,13 @@
 using ResourceMember = PrimitiveMember<ResourceId>;
 using StringMember = PrimitiveMember<std::string>;
 
-template <typename T>
+template <typename T, typename StringConverter>
 class PrimitiveArrayMember : public ClassMember {
  public:
   explicit PrimitiveArrayMember(const android::StringPiece& name) : name_(name.to_string()) {}
 
   void AddElement(const T& val) {
-    elements_.push_back(val);
+    elements_.emplace_back(val);
   }
 
   bool empty() const override {
@@ -158,7 +158,7 @@
         printer->Println();
       }
 
-      printer->Print(to_string(*current));
+      printer->Print(StringConverter::ToString(*current));
       if (std::distance(current, end) > 1) {
         printer->Print(", ");
       }
@@ -175,7 +175,24 @@
   std::vector<T> elements_;
 };
 
-using ResourceArrayMember = PrimitiveArrayMember<ResourceId>;
+struct FieldReference {
+  explicit FieldReference(std::string reference) : ref(std::move(reference)) {
+  }
+  std::string ref;
+};
+
+struct ResourceArrayMemberStringConverter {
+  static std::string ToString(const std::variant<ResourceId, FieldReference>& ref) {
+    if (auto id = std::get_if<ResourceId>(&ref)) {
+      return to_string(*id);
+    } else {
+      return std::get<FieldReference>(ref).ref;
+    }
+  }
+};
+
+using ResourceArrayMember = PrimitiveArrayMember<std::variant<ResourceId, FieldReference>,
+                                                 ResourceArrayMemberStringConverter>;
 
 // Represents a method in a class.
 class MethodDefinition : public ClassMember {
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index f0f839d..59dd481 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -224,7 +224,16 @@
   return cmp_ids_dynamic_after_framework(lhs_id, rhs_id);
 }
 
-void JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const ResourceId& id,
+static FieldReference GetRFieldReference(const ResourceName& name,
+                                         StringPiece fallback_package_name) {
+  const std::string package_name =
+      name.package.empty() ? fallback_package_name.to_string() : name.package;
+  const std::string entry = JavaClassGenerator::TransformToFieldName(name.entry);
+  return FieldReference(
+      StringPrintf("%s.R.%s.%s", package_name.c_str(), to_string(name.type).data(), entry.c_str()));
+}
+
+bool JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const ResourceId& id,
                                           const Styleable& styleable,
                                           const StringPiece& package_name_to_generate,
                                           ClassDefinition* out_class_def,
@@ -340,14 +349,29 @@
 
   // Add the ResourceIds to the array member.
   for (size_t i = 0; i < attr_count; i++) {
-    const ResourceId id = sorted_attributes[i].attr_ref->id.value_or_default(ResourceId(0));
-    array_def->AddElement(id);
+    const StyleableAttr& attr = sorted_attributes[i];
+    std::string r_txt_contents;
+    if (attr.symbol && attr.symbol.value().is_dynamic) {
+      if (!attr.attr_ref->name) {
+        error_ = "unable to determine R.java field name of dynamic resource";
+        return false;
+      }
+
+      const FieldReference field_name =
+          GetRFieldReference(attr.attr_ref->name.value(), package_name_to_generate);
+      array_def->AddElement(field_name);
+      r_txt_contents = field_name.ref;
+    } else {
+      const ResourceId attr_id = attr.attr_ref->id.value_or_default(ResourceId(0));
+      array_def->AddElement(attr_id);
+      r_txt_contents = to_string(attr_id);
+    }
 
     if (r_txt_printer != nullptr) {
       if (i != 0) {
         r_txt_printer->Print(",");
       }
-      r_txt_printer->Print(" ").Print(id.to_string());
+      r_txt_printer->Print(" ").Print(r_txt_contents);
     }
   }
 
@@ -419,19 +443,7 @@
     }
   }
 
-  // If there is a rewrite method to generate, add the statements that rewrite package IDs
-  // for this styleable.
-  if (out_rewrite_method != nullptr) {
-    out_rewrite_method->AppendStatement(
-        StringPrintf("for (int i = 0; i < styleable.%s.length; i++) {", array_field_name.data()));
-    out_rewrite_method->AppendStatement(
-        StringPrintf("  if ((styleable.%s[i] & 0xff000000) == 0) {", array_field_name.data()));
-    out_rewrite_method->AppendStatement(
-        StringPrintf("    styleable.%s[i] = (styleable.%s[i] & 0x00ffffff) | packageIdBits;",
-                     array_field_name.data(), array_field_name.data()));
-    out_rewrite_method->AppendStatement("  }");
-    out_rewrite_method->AppendStatement("}");
-  }
+  return true;
 }
 
 void JavaClassGenerator::ProcessResource(const ResourceNameRef& name, const ResourceId& id,
@@ -448,8 +460,7 @@
 
   const std::string field_name = TransformToFieldName(name.entry);
   if (out_class_def != nullptr) {
-    std::unique_ptr<ResourceMember> resource_member =
-        util::make_unique<ResourceMember>(field_name, real_id);
+    auto resource_member = util::make_unique<ResourceMember>(field_name, real_id);
 
     // Build the comments and annotations for this entry.
     AnnotationProcessor* processor = resource_member->GetCommentBuilder();
@@ -551,12 +562,11 @@
 
     if (resource_name.type == ResourceType::kStyleable) {
       CHECK(!entry->values.empty());
-
-      const Styleable* styleable =
-          static_cast<const Styleable*>(entry->values.front()->value.get());
-
-      ProcessStyleable(resource_name, id, *styleable, package_name_to_generate, out_type_class_def,
-                       out_rewrite_method_def, r_txt_printer);
+      const auto styleable = reinterpret_cast<const Styleable*>(entry->values.front()->value.get());
+      if (!ProcessStyleable(resource_name, id, *styleable, package_name_to_generate,
+                            out_type_class_def, out_rewrite_method_def, r_txt_printer)) {
+        return false;
+      }
     } else {
       ProcessResource(resource_name, id, *entry, out_type_class_def, out_rewrite_method_def,
                       r_txt_printer);
@@ -626,8 +636,7 @@
 
       if (type->type == ResourceType::kAttr) {
         // Also include private attributes in this same class.
-        const ResourceTableType* priv_type = package->FindType(ResourceType::kAttrPrivate);
-        if (priv_type) {
+        if (const ResourceTableType* priv_type = package->FindType(ResourceType::kAttrPrivate)) {
           if (!ProcessType(package_name_to_generate, *package, *priv_type, class_def.get(),
                            rewrite_method.get(), r_txt_printer.get())) {
             return false;
diff --git a/tools/aapt2/java/JavaClassGenerator.h b/tools/aapt2/java/JavaClassGenerator.h
index 853120b..d9d1b39 100644
--- a/tools/aapt2/java/JavaClassGenerator.h
+++ b/tools/aapt2/java/JavaClassGenerator.h
@@ -105,7 +105,7 @@
   // Writes a styleable resource to the R.java file, optionally writing out a rewrite rule for
   // its package ID if `out_rewrite_method` is not nullptr.
   // `package_name_to_generate` is the package
-  void ProcessStyleable(const ResourceNameRef& name, const ResourceId& id,
+  bool ProcessStyleable(const ResourceNameRef& name, const ResourceId& id,
                         const Styleable& styleable,
                         const android::StringPiece& package_name_to_generate,
                         ClassDefinition* out_class_def, MethodDefinition* out_rewrite_method,
diff --git a/tools/aapt2/java/JavaClassGenerator_test.cpp b/tools/aapt2/java/JavaClassGenerator_test.cpp
index 04e2010..ec5b415 100644
--- a/tools/aapt2/java/JavaClassGenerator_test.cpp
+++ b/tools/aapt2/java/JavaClassGenerator_test.cpp
@@ -581,7 +581,7 @@
   out.Flush();
 
   EXPECT_THAT(output, HasSubstr("public static final int[] MyStyleable={"));
-  EXPECT_THAT(output, HasSubstr("0x01010000, 0x00010000"));
+  EXPECT_THAT(output, HasSubstr("0x01010000, lib.R.attr.dynamic_attr"));
   EXPECT_THAT(output, HasSubstr("public static final int MyStyleable_android_framework_attr=0;"));
   EXPECT_THAT(output, HasSubstr("public static final int MyStyleable_dynamic_attr=1;"));
 }
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index daedc2a..98ee63d 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -370,11 +370,11 @@
   } else {
     s = util::make_unique<SymbolTable::Symbol>();
     s->id = res_id;
-    s->is_dynamic = IsPackageDynamic(ResourceId(res_id).package_id(), real_name.package);
   }
 
   if (s) {
     s->is_public = (type_spec_flags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
+    s->is_dynamic = IsPackageDynamic(ResourceId(res_id).package_id(), real_name.package);
     return s;
   }
   return {};
@@ -417,11 +417,11 @@
   } else {
     s = util::make_unique<SymbolTable::Symbol>();
     s->id = id;
-    s->is_dynamic = IsPackageDynamic(ResourceId(id).package_id(), name.package);
   }
 
   if (s) {
     s->is_public = (*flags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
+    s->is_dynamic = IsPackageDynamic(ResourceId(id).package_id(), name.package);
     return s;
   }
   return {};
diff --git a/tools/aapt2/test/Fixture.cpp b/tools/aapt2/test/Fixture.cpp
index 5386802..f94f0fe 100644
--- a/tools/aapt2/test/Fixture.cpp
+++ b/tools/aapt2/test/Fixture.cpp
@@ -18,18 +18,17 @@
 
 #include <dirent.h>
 
-#include "android-base/errors.h"
-#include "android-base/file.h"
-#include "android-base/stringprintf.h"
-#include "android-base/utf8.h"
-#include "androidfw/StringPiece.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
+#include <android-base/errors.h>
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/utf8.h>
+#include <androidfw/StringPiece.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
 
 #include "cmd/Compile.h"
 #include "cmd/Link.h"
 #include "io/FileStream.h"
-#include "io/Util.h"
 #include "util/Files.h"
 
 using testing::Eq;
@@ -170,4 +169,74 @@
   }
 }
 
+ManifestBuilder::ManifestBuilder(CommandTestFixture* fixture) : fixture_(fixture) {
+}
+
+ManifestBuilder& ManifestBuilder::SetPackageName(const std::string& package_name) {
+  package_name_ = package_name;
+  return *this;
+}
+
+ManifestBuilder& ManifestBuilder::AddContents(const std::string& contents) {
+  contents_ += contents + "\n";
+  return *this;
+}
+
+std::string ManifestBuilder::Build(const std::string& file_path) {
+  const char* manifest_template = R"(
+      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="%s">
+          %s
+      </manifest>)";
+
+  fixture_->WriteFile(file_path, android::base::StringPrintf(
+                                     manifest_template, package_name_.c_str(), contents_.c_str()));
+  return file_path;
+}
+
+std::string ManifestBuilder::Build() {
+  return Build(fixture_->GetTestPath("AndroidManifest.xml"));
+}
+
+LinkCommandBuilder::LinkCommandBuilder(CommandTestFixture* fixture) : fixture_(fixture) {
+}
+
+LinkCommandBuilder& LinkCommandBuilder::SetManifestFile(const std::string& file) {
+  manifest_supplied_ = true;
+  args_.emplace_back("--manifest");
+  args_.emplace_back(file);
+  return *this;
+}
+
+LinkCommandBuilder& LinkCommandBuilder::AddFlag(const std::string& flag) {
+  args_.emplace_back(flag);
+  return *this;
+}
+
+LinkCommandBuilder& LinkCommandBuilder::AddCompiledResDir(const std::string& dir,
+                                                          IDiagnostics* diag) {
+  if (auto files = file::FindFiles(dir, diag)) {
+    for (std::string& compile_file : files.value()) {
+      args_.emplace_back(file::BuildPath({dir, compile_file}));
+    }
+  }
+  return *this;
+}
+
+LinkCommandBuilder& LinkCommandBuilder::AddParameter(const std::string& param,
+                                                     const std::string& value) {
+  args_.emplace_back(param);
+  args_.emplace_back(value);
+  return *this;
+}
+
+std::vector<std::string> LinkCommandBuilder::Build(const std::string& out_apk) {
+  if (!manifest_supplied_) {
+    SetManifestFile(ManifestBuilder(fixture_).Build());
+  }
+  args_.emplace_back("-o");
+  args_.emplace_back(out_apk);
+  return args_;
+}
+
 } // namespace aapt
\ No newline at end of file
diff --git a/tools/aapt2/test/Fixture.h b/tools/aapt2/test/Fixture.h
index 457d65e..f8c4889 100644
--- a/tools/aapt2/test/Fixture.h
+++ b/tools/aapt2/test/Fixture.h
@@ -32,7 +32,7 @@
 class TestDirectoryFixture : public ::testing::Test {
  public:
   TestDirectoryFixture() = default;
-  virtual ~TestDirectoryFixture() = default;
+  ~TestDirectoryFixture() override = default;
 
   // Creates the test directory or clears its contents if it contains previously created files.
   void SetUp() override;
@@ -41,14 +41,14 @@
   void TearDown() override;
 
   // Retrieve the test directory of the fixture.
-  const android::StringPiece GetTestDirectory() {
+  android::StringPiece GetTestDirectory() {
     return temp_dir_;
   }
 
   // Retrieves the absolute path of the specified relative path in the test directory. Directories
   // should be separated using forward slashes ('/'), and these slashes will be translated to
   // backslashes when running Windows tests.
-  const std::string GetTestPath(const android::StringPiece& path) {
+  std::string GetTestPath(const android::StringPiece& path) {
     std::string base = temp_dir_;
     for (android::StringPiece part : util::Split(path, '/')) {
       file::AppendPath(&base, part);
@@ -68,7 +68,7 @@
 class CommandTestFixture : public TestDirectoryFixture {
  public:
   CommandTestFixture() = default;
-  virtual ~CommandTestFixture() = default;
+  ~CommandTestFixture() override = default;
 
   // Wries the contents of the file to the specified path. The file is compiled and the flattened
   // file is written to the out directory.
@@ -99,6 +99,33 @@
   DISALLOW_COPY_AND_ASSIGN(CommandTestFixture);
 };
 
+struct ManifestBuilder {
+  explicit ManifestBuilder(CommandTestFixture* fixture);
+  ManifestBuilder& AddContents(const std::string& contents);
+  ManifestBuilder& SetPackageName(const std::string& package_name);
+  std::string Build(const std::string& file_path);
+  std::string Build();
+
+ private:
+  CommandTestFixture* fixture_;
+  std::string package_name_ = CommandTestFixture::kDefaultPackageName;
+  std::string contents_;
+};
+
+struct LinkCommandBuilder {
+  explicit LinkCommandBuilder(CommandTestFixture* fixture);
+  LinkCommandBuilder& AddCompiledResDir(const std::string& dir, IDiagnostics* diag);
+  LinkCommandBuilder& AddFlag(const std::string& flag);
+  LinkCommandBuilder& AddParameter(const std::string& param, const std::string& value);
+  LinkCommandBuilder& SetManifestFile(const std::string& manifest_path);
+  std::vector<std::string> Build(const std::string& out_apk_path);
+
+ private:
+  CommandTestFixture* fixture_;
+  std::vector<std::string> args_;
+  bool manifest_supplied_ = false;
+};
+
 } // namespace aapt
 
 #endif  // AAPT_TEST_FIXTURE_H
\ No newline at end of file
diff --git a/tools/bit/make.cpp b/tools/bit/make.cpp
index df64a80..c39f494 100644
--- a/tools/bit/make.cpp
+++ b/tools/bit/make.cpp
@@ -89,8 +89,9 @@
     }
 
     Json::Value json;
-    Json::Reader reader;
-    if (!reader.parse(stream, json)) {
+    Json::CharReaderBuilder builder;
+    std::string errorMessage;
+    if (!Json::parseFromStream(builder, stream, &json, &errorMessage)) {
         return;
     }
 
@@ -132,8 +133,9 @@
         return;
     }
 
-    Json::StyledStreamWriter writer("  ");
-
+    Json::StreamWriterBuilder factory;
+    factory["indentation"] = "  ";
+    std::unique_ptr<Json::StreamWriter> const writer(factory.newStreamWriter());
     Json::Value json(Json::objectValue);
 
     for (map<string,string>::const_iterator it = m_cache.begin(); it != m_cache.end(); it++) {
@@ -141,7 +143,7 @@
     }
 
     std::ofstream stream(m_filename, std::ofstream::binary);
-    writer.write(stream, json);
+    writer->write(json, &stream);
 }
 
 string
@@ -212,8 +214,9 @@
     }
 
     Json::Value json;
-    Json::Reader reader;
-    if (!reader.parse(stream, json)) {
+    Json::CharReaderBuilder builder;
+    std::string errorMessage;
+    if (!Json::parseFromStream(builder, stream, &json, &errorMessage)) {
         json_error(filename, "can't parse json format", quiet);
         return;
     }
diff --git a/tools/fonts/fontchain_linter.py b/tools/fonts/fontchain_linter.py
index f0b7595..e775e1a 100755
--- a/tools/fonts/fontchain_linter.py
+++ b/tools/fonts/fontchain_linter.py
@@ -665,6 +665,51 @@
             assert_font_supports_none_of_chars(record.font, cjk_punctuation, name)
 
 
+def getPostScriptName(font):
+  ttf = open_font(font)
+  nameTable = ttf['name']
+  for name in nameTable.names:
+    if name.nameID == 6 and name.platformID == 3 and name.platEncID == 1 and name.langID == 0x0409:
+      return str(name)
+
+
+def getSuffix(font):
+  file_path, index = font
+  with open(path.join(_fonts_dir, file_path), 'rb') as f:
+    tag = f.read(4)
+    isCollection = tag == b'ttcf'
+
+  ttf = open_font(font)
+  isType1 = ('CFF ' in ttf or 'CFF2' in ttf)
+
+  if isType1:
+    if isCollection:
+      return '.otc'
+    else:
+      return '.otf'
+  else:
+    if isCollection:
+      return '.ttc'
+    else:
+      return '.ttf'
+
+
+def check_canonical_name():
+  for record in _all_fonts:
+    file_name, index = record.font
+
+    if index and index != 0:
+      continue
+
+    psName = getPostScriptName(record.font)
+    assert psName, 'PostScript must be defined'
+
+    suffix = getSuffix(record.font)
+    canonicalName = '%s%s' % (psName, suffix)
+
+    assert file_name == canonicalName, (
+        '%s is not a canonical name. Must be %s' % (file_name, canonicalName))
+
 def main():
     global _fonts_dir
     target_out = sys.argv[1]
@@ -682,6 +727,8 @@
 
     check_cjk_punctuation()
 
+    check_canonical_name()
+
     check_emoji = sys.argv[2]
     if check_emoji == 'true':
         ucd_path = sys.argv[3]
diff --git a/tools/powerstats/Android.bp b/tools/powerstats/Android.bp
index af41144..9c58daf0 100644
--- a/tools/powerstats/Android.bp
+++ b/tools/powerstats/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 java_binary_host {
     name: "PowerStatsServiceProtoParser",
     manifest: "PowerStatsServiceProtoParser_manifest.txt",
diff --git a/tools/processors/intdef_mappings/Android.bp b/tools/processors/intdef_mappings/Android.bp
index e255f7c..82a5dac 100644
--- a/tools/processors/intdef_mappings/Android.bp
+++ b/tools/processors/intdef_mappings/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 java_plugin {
     name: "intdef-annotation-processor",
 
@@ -30,4 +39,4 @@
     ],
 
     test_suites: ["general-tests"],
-}
\ No newline at end of file
+}
diff --git a/tools/protologtool/Android.bp b/tools/protologtool/Android.bp
index 4342d4e..039bb4e 100644
--- a/tools/protologtool/Android.bp
+++ b/tools/protologtool/Android.bp
@@ -34,9 +34,13 @@
     srcs: [
         "tests/**/*.kt",
     ],
+    test_options: {
+        unit_test: true,
+    },
     static_libs: [
         "protologtool-lib",
         "junit",
         "mockito",
+        "objenesis",
     ],
 }
diff --git a/tools/xmlpersistence/Android.bp b/tools/xmlpersistence/Android.bp
index d58d0dc..0b6dba6 100644
--- a/tools/xmlpersistence/Android.bp
+++ b/tools/xmlpersistence/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 java_binary_host {
     name: "xmlpersistence_cli",
     manifest: "manifest.txt",